From ead687da06543861b465ab110aad13d5a995b15c Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Tue, 21 Jan 2020 15:28:01 +0100 Subject: [PATCH 001/429] Python: Add false positive test example for issue #2652. --- .../Variables/unused/UnusedLocalVariable.expected | 1 + .../Variables/unused/type_annotation_fp.py | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 python/ql/test/query-tests/Variables/unused/type_annotation_fp.py diff --git a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected index a902cad04cb..339a74432bc 100644 --- a/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected +++ b/python/ql/test/query-tests/Variables/unused/UnusedLocalVariable.expected @@ -1,3 +1,4 @@ +| type_annotation_fp.py:5:5:5:7 | foo | The value assigned to local variable 'foo' is never used. | | variables_test.py:29:5:29:5 | x | The value assigned to local variable 'x' is never used. | | variables_test.py:89:5:89:5 | a | The value assigned to local variable 'a' is never used. | | variables_test.py:89:7:89:7 | b | The value assigned to local variable 'b' is never used. | diff --git a/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py b/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py new file mode 100644 index 00000000000..72293f232e5 --- /dev/null +++ b/python/ql/test/query-tests/Variables/unused/type_annotation_fp.py @@ -0,0 +1,11 @@ +# FP Type annotation counts as redefinition +# See https://github.com/Semmle/ql/issues/2652 + +def type_annotation(x): + foo = 5 + if x: + foo : int + do_stuff_with(foo) + else: + foo : float + do_other_stuff_with(foo) From 4ec78d04f8cc8f869af959556e9537bf651fd7e5 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 21 Dec 2020 00:15:15 +0000 Subject: [PATCH 002/429] Insecure LDAP authentication --- .../CWE/CWE-522/InsecureLdapAuth.java | 24 +++ .../CWE/CWE-522/InsecureLdapAuth.qhelp | 32 ++++ .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 153 ++++++++++++++++++ .../CWE-522/InsecureLdapAuth.expected | 15 ++ .../security/CWE-522/InsecureLdapAuth.java | 92 +++++++++++ .../security/CWE-522/InsecureLdapAuth.qlref | 1 + 6 files changed, 317 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java new file mode 100644 index 00000000000..33764506a1b --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java @@ -0,0 +1,24 @@ +public class InsecureLdapAuth { + /** LDAP authentication */ + public DirContext ldapAuth(String ldapUserName, String password) { + { + // BAD: LDAP authentication in cleartext + String ldapUrl = "ldap://ad.your-server.com:389"; + } + + { + // GOOD: LDAPS authentication over SSL + String ldapUrl = "ldaps://ad.your-server.com:636"; + } + + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + DirContext dirContext = new InitialDirContext(environment); + return dirContext; + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp new file mode 100644 index 00000000000..9b7193bf52f --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp @@ -0,0 +1,32 @@ + + + + +

When using the Java LDAP API to perform LDAPv3-style extended operations and controls, a context with connection properties including user credentials is started. Transmission of LDAP credentials in cleartext allows remote attackers to obtain sensitive information by sniffing the network.

+
+ + +

Use LDAPS to send credentials through SSL or use SASL authentication.

+
+ + +

The following example shows two ways of using LDAP authentication. In the 'BAD' case, the credentials are transmitted in cleartext. In the 'GOOD' case, the credentials are transmitted over SSL.

+ +
+ + +
  • + CWE: + CWE-522: Insufficiently Protected Credentials + CWE-319: Cleartext Transmission of Sensitive Information +
  • +
  • + Oracle: + LDAP and LDAPS URLs +
  • +
  • + Oracle: + Simple authentication consists of sending the LDAP server the fully qualified DN of the client (user) and the client's clear-text password +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql new file mode 100644 index 00000000000..663f4110524 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -0,0 +1,153 @@ +/** + * @name Insecure LDAP authentication + * @description LDAP authentication with credentials sent in cleartext. + * @kind path-problem + * @id java/insecure-ldap-auth + * @tags security + * external/cwe-522 + * external/cwe-319 + */ + +import java +import semmle.code.java.frameworks.Jndi +import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph + +/** + * Gets a regular expression for matching private hosts, which only matches the host portion therefore checking for port is not necessary. + */ +private string getPrivateHostRegex() { + result = + "(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?" +} + +/** + * String of LDAP connections not in private domains. + */ +class LdapStringLiteral extends StringLiteral { + LdapStringLiteral() { + // Match connection strings with the LDAP protocol and without private IP addresses to reduce false positives. + exists(string s | this.getRepresentedString() = s | + s.regexpMatch("(?i)ldap://[\\[a-zA-Z0-9].*") and + not s.substring(7, s.length()).regexpMatch(getPrivateHostRegex()) + ) + } +} + +/** The interface `javax.naming.Context`. */ +class TypeNamingContext extends Interface { + TypeNamingContext() { this.hasQualifiedName("javax.naming", "Context") } +} + +/** The class `java.util.Hashtable`. */ +class TypeHashtable extends Class { + TypeHashtable() { this.getSourceDeclaration().hasQualifiedName("java.util", "Hashtable") } +} + +/** + * Holds if a non-private LDAP string is concatenated from both protocol and host. + */ +predicate concatLdapString(Expr protocol, Expr host) { + ( + protocol.(CompileTimeConstantExpr).getStringValue().regexpMatch("(?i)ldap(://)?") or + protocol + .(VarAccess) + .getVariable() + .getAnAssignedValue() + .(CompileTimeConstantExpr) + .getStringValue() + .regexpMatch("(?i)ldap(://)?") + ) and + not exists(string hostString | + hostString = host.(CompileTimeConstantExpr).getStringValue() or + hostString = + host.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getStringValue() + | + hostString.length() = 0 or // Empty host is loopback address + hostString.regexpMatch(getPrivateHostRegex()) + ) +} + +/** Gets the leftmost operand in a concatenated string */ +Expr getLeftmostConcatOperand(Expr expr) { + if expr instanceof AddExpr + then result = getLeftmostConcatOperand(expr.(AddExpr).getLeftOperand()) + else result = expr +} + +/** + * String concatenated with `LdapStringLiteral`. + */ +class LdapString extends Expr { + LdapString() { + this instanceof LdapStringLiteral + or + concatLdapString(this.(AddExpr).getLeftOperand(), + getLeftmostConcatOperand(this.(AddExpr).getRightOperand())) + } +} + +/** + * Tainted value passed to env `Hashtable` as the provider URL, i.e. + * `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`. + */ +predicate isProviderUrlEnv(MethodAccess ma) { + ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and + (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and + ( + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url" + or + exists(Field f | + ma.getArgument(0) = f.getAnAccess() and + f.hasName("PROVIDER_URL") and + f.getDeclaringType() instanceof TypeNamingContext + ) + ) +} + +/** + * Holds if the value "simple" is passed to env `Hashtable` as the authentication mechanism, i.e. + * `env.put(Context.SECURITY_AUTHENTICATION, "simple")` or `env.setProperty(Context.SECURITY_AUTHENTICATION, "simple")`. + */ +predicate isSimpleAuthEnv(MethodAccess ma) { + ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and + (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and + ( + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = + "java.naming.security.authentication" + or + exists(Field f | + ma.getArgument(0) = f.getAnAccess() and + f.hasName("SECURITY_AUTHENTICATION") and + f.getDeclaringType() instanceof TypeNamingContext + ) + ) and + ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "simple" +} + +/** + * A taint-tracking configuration for cleartext credentials in LDAP authentication. + */ +class LdapAuthFlowConfig extends TaintTracking::Configuration { + LdapAuthFlowConfig() { this = "InsecureLdapAuth:LdapAuthFlowConfig" } + + /** Source of non-private LDAP connection string */ + override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LdapString } + + /** Sink of provider URL with simple authentication */ + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess pma | + sink.asExpr() = pma.getArgument(1) and + isProviderUrlEnv(pma) and + exists(MethodAccess sma | + sma.getQualifier() = pma.getQualifier().(VarAccess).getVariable().getAnAccess() and + isSimpleAuthEnv(sma) + ) + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, LdapAuthFlowConfig config +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Insecure LDAP authentication from $@.", source.getNode(), + "LDAP connection string" diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected new file mode 100644 index 00000000000..65abcef0a9b --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected @@ -0,0 +1,15 @@ +edges +| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | +| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | +| InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | +nodes +| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | +| InsecureLdapAuth.java:15:41:15:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | semmle.label | ... + ... : String | +| InsecureLdapAuth.java:29:41:29:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | +| InsecureLdapAuth.java:85:41:85:47 | ldapUrl | semmle.label | ldapUrl | +#select +| InsecureLdapAuth.java:15:41:15:47 | ldapUrl | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:29:41:29:47 | ldapUrl | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:25:20:25:39 | ... + ... | LDAP connection string | +| InsecureLdapAuth.java:85:41:85:47 | ldapUrl | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" | LDAP connection string | diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java new file mode 100644 index 00000000000..236880a1e8e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java @@ -0,0 +1,92 @@ +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.ldap.InitialLdapContext; + +public class InsecureLdapAuth { + // BAD - Test LDAP authentication in cleartext using `DirContext`. + public void testCleartextLdapAuth(String ldapUserName, String password) { + String ldapUrl = "ldap://ad.your-server.com:389"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + DirContext dirContext = new InitialDirContext(environment); + } + + // BAD - Test LDAP authentication in cleartext using `DirContext`. + public void testCleartextLdapAuth(String ldapUserName, String password, String serverName) { + String ldapUrl = "ldap://"+serverName+":389"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + DirContext dirContext = new InitialDirContext(environment); + } + + // GOOD - Test LDAP authentication over SSL. + public void testSslLdapAuth(String ldapUserName, String password) { + String ldapUrl = "ldaps://ad.your-server.com:636"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + DirContext dirContext = new InitialDirContext(environment); + } + + // GOOD - Test LDAP authentication with SASL authentication. + public void testSaslLdapAuth(String ldapUserName, String password) { + String ldapUrl = "ldap://ad.your-server.com:389"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5 GSSAPI"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + DirContext dirContext = new InitialDirContext(environment); + } + + // GOOD - Test LDAP authentication in cleartext connecting to local LDAP server. + public void testCleartextLdapAuth2(String ldapUserName, String password) { + String ldapUrl = "ldap://localhost:389"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + DirContext dirContext = new InitialDirContext(environment); + } + + // BAD - Test LDAP authentication in cleartext using `InitialLdapContext`. + public void testCleartextLdapAuth3(String ldapUserName, String password) { + String ldapUrl = "ldap://ad.your-server.com:389"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + InitialLdapContext ldapContext = new InitialLdapContext(environment, null); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.qlref b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.qlref new file mode 100644 index 00000000000..c2baa984177 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql From c069a5b4c654e06ea669e7cdef0793d5179c9944 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 4 Jan 2021 14:51:32 +0000 Subject: [PATCH 003/429] Factor private host regex into the networking library and enhance the query --- .../Security/CWE/CWE-522/InsecureBasicAuth.ql | 12 +---- .../CWE/CWE-522/InsecureLdapAuth.qhelp | 2 +- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 54 +++++++------------ .../code/java/frameworks/Networking.qll | 10 ++++ .../CWE-522/InsecureLdapAuth.expected | 4 ++ .../security/CWE-522/InsecureLdapAuth.java | 15 ++++++ 6 files changed, 50 insertions(+), 47 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql index 1fadb5bda69..3ec836a0117 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureBasicAuth.ql @@ -14,14 +14,6 @@ import semmle.code.java.frameworks.ApacheHttp import semmle.code.java.dataflow.TaintTracking import DataFlow::PathGraph -/** - * Gets a regular expression for matching private hosts, which only matches the host portion therefore checking for port is not necessary. - */ -private string getPrivateHostRegex() { - result = - "(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?" -} - /** * Class of Java URL constructor. */ @@ -76,7 +68,7 @@ class HttpStringLiteral extends StringLiteral { // Match URLs with the HTTP protocol and without private IP addresses to reduce false positives. exists(string s | this.getRepresentedString() = s | s.regexpMatch("(?i)http://[\\[a-zA-Z0-9].*") and - not s.substring(7, s.length()).regexpMatch(getPrivateHostRegex()) + not s.substring(7, s.length()) instanceof PrivateHostName ) } } @@ -101,7 +93,7 @@ predicate concatHttpString(Expr protocol, Expr host) { host.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getStringValue() | hostString.length() = 0 or // Empty host is loopback address - hostString.regexpMatch(getPrivateHostRegex()) + hostString instanceof PrivateHostName ) } diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp index 9b7193bf52f..9241b52cf19 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp @@ -11,7 +11,7 @@

    The following example shows two ways of using LDAP authentication. In the 'BAD' case, the credentials are transmitted in cleartext. In the 'GOOD' case, the credentials are transmitted over SSL.

    - +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 663f4110524..37b3057fb2f 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -10,26 +10,19 @@ import java import semmle.code.java.frameworks.Jndi +import semmle.code.java.frameworks.Networking import semmle.code.java.dataflow.TaintTracking import DataFlow::PathGraph /** - * Gets a regular expression for matching private hosts, which only matches the host portion therefore checking for port is not necessary. + * Insecure (non-SSL, non-private) LDAP URL string literal. */ -private string getPrivateHostRegex() { - result = - "(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?" -} - -/** - * String of LDAP connections not in private domains. - */ -class LdapStringLiteral extends StringLiteral { - LdapStringLiteral() { +class InsecureLdapUrlLiteral extends StringLiteral { + InsecureLdapUrlLiteral() { // Match connection strings with the LDAP protocol and without private IP addresses to reduce false positives. exists(string s | this.getRepresentedString() = s | s.regexpMatch("(?i)ldap://[\\[a-zA-Z0-9].*") and - not s.substring(7, s.length()).regexpMatch(getPrivateHostRegex()) + not s.substring(7, s.length()) instanceof PrivateHostName ) } } @@ -47,24 +40,15 @@ class TypeHashtable extends Class { /** * Holds if a non-private LDAP string is concatenated from both protocol and host. */ -predicate concatLdapString(Expr protocol, Expr host) { - ( - protocol.(CompileTimeConstantExpr).getStringValue().regexpMatch("(?i)ldap(://)?") or - protocol - .(VarAccess) - .getVariable() - .getAnAssignedValue() - .(CompileTimeConstantExpr) - .getStringValue() - .regexpMatch("(?i)ldap(://)?") - ) and +predicate concatInsecureLdapString(Expr protocol, Expr host) { + protocol.(CompileTimeConstantExpr).getStringValue() = "ldap://" and not exists(string hostString | hostString = host.(CompileTimeConstantExpr).getStringValue() or hostString = host.(VarAccess).getVariable().getAnAssignedValue().(CompileTimeConstantExpr).getStringValue() | hostString.length() = 0 or // Empty host is loopback address - hostString.regexpMatch(getPrivateHostRegex()) + hostString instanceof PrivateHostName ) } @@ -76,22 +60,21 @@ Expr getLeftmostConcatOperand(Expr expr) { } /** - * String concatenated with `LdapStringLiteral`. + * String concatenated with `InsecureLdapUrlLiteral`. */ -class LdapString extends Expr { - LdapString() { - this instanceof LdapStringLiteral +class InsecureLdapUrl extends Expr { + InsecureLdapUrl() { + this instanceof InsecureLdapUrlLiteral or - concatLdapString(this.(AddExpr).getLeftOperand(), + concatInsecureLdapString(this.(AddExpr).getLeftOperand(), getLeftmostConcatOperand(this.(AddExpr).getRightOperand())) } } /** - * Tainted value passed to env `Hashtable` as the provider URL, i.e. - * `env.put(Context.PROVIDER_URL, tainted)` or `env.setProperty(Context.PROVIDER_URL, tainted)`. + * Holds if `ma` writes the `java.naming.provider.url` (also known as `Context.PROVIDER_URL`) key of a `Hashtable`. */ -predicate isProviderUrlEnv(MethodAccess ma) { +predicate isProviderUrlSetter(MethodAccess ma) { ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and ( @@ -106,8 +89,7 @@ predicate isProviderUrlEnv(MethodAccess ma) { } /** - * Holds if the value "simple" is passed to env `Hashtable` as the authentication mechanism, i.e. - * `env.put(Context.SECURITY_AUTHENTICATION, "simple")` or `env.setProperty(Context.SECURITY_AUTHENTICATION, "simple")`. + * Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`. */ predicate isSimpleAuthEnv(MethodAccess ma) { ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and @@ -132,13 +114,13 @@ class LdapAuthFlowConfig extends TaintTracking::Configuration { LdapAuthFlowConfig() { this = "InsecureLdapAuth:LdapAuthFlowConfig" } /** Source of non-private LDAP connection string */ - override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LdapString } + override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof InsecureLdapUrl } /** Sink of provider URL with simple authentication */ override predicate isSink(DataFlow::Node sink) { exists(MethodAccess pma | sink.asExpr() = pma.getArgument(1) and - isProviderUrlEnv(pma) and + isProviderUrlSetter(pma) and exists(MethodAccess sma | sma.getQualifier() = pma.getQualifier().(VarAccess).getVariable().getAnAccess() and isSimpleAuthEnv(sma) diff --git a/java/ql/src/semmle/code/java/frameworks/Networking.qll b/java/ql/src/semmle/code/java/frameworks/Networking.qll index 988510dd2e9..997b8075403 100644 --- a/java/ql/src/semmle/code/java/frameworks/Networking.qll +++ b/java/ql/src/semmle/code/java/frameworks/Networking.qll @@ -129,3 +129,13 @@ class UrlOpenConnectionMethod extends Method { this.getName() = "openConnection" } } + +/** + * A string matching private host names of IPv4 and IPv6, which only matches the host portion therefore checking for port is not necessary. + */ +class PrivateHostName extends string { + bindingset[this] + PrivateHostName() { + this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?") + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected index 65abcef0a9b..c34c8966e0d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected @@ -2,6 +2,7 @@ edges | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | +| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:47:100:53 | ldapUrl | nodes | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | semmle.label | ldapUrl | @@ -9,7 +10,10 @@ nodes | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | semmle.label | ldapUrl | | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | +| InsecureLdapAuth.java:100:47:100:53 | ldapUrl | semmle.label | ldapUrl | #select | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" | LDAP connection string | | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:25:20:25:39 | ... + ... | LDAP connection string | | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:100:47:100:53 | ldapUrl | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:47:100:53 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" | LDAP connection string | diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java index 236880a1e8e..cc16047ebf2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java @@ -89,4 +89,19 @@ public class InsecureLdapAuth { environment.put(Context.SECURITY_CREDENTIALS, password); InitialLdapContext ldapContext = new InitialLdapContext(environment, null); } + + + // BAD - Test LDAP authentication in cleartext using `DirContext` and string literals. + public void testCleartextLdapAuth4(String ldapUserName, String password) { + String ldapUrl = "ldap://ad.your-server.com:389"; + Hashtable environment = new Hashtable(); + environment.put("java.naming.factory.initial", + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put("java.naming.provider.url", ldapUrl); + environment.put("java.naming.referral", "follow"); + environment.put("java.naming.security.authentication", "simple"); + environment.put("java.naming.security.principal", ldapUserName); + environment.put("java.naming.security.credentials", password); + DirContext dirContext = new InitialDirContext(environment); + } } From 9b3070ab7c061b6d61f8e282c4e1272803750c6c Mon Sep 17 00:00:00 2001 From: intrigus Date: Tue, 12 Jan 2021 14:48:22 +0100 Subject: [PATCH 004/429] Java: Add JXBrowser disabled certificate query. --- .../JXBrowserWithoutCertValidation.java | 23 ++++++ .../JXBrowserWithoutCertValidation.qhelp | 31 ++++++++ .../CWE-295/JXBrowserWithoutCertValidation.ql | 73 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.java b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.java new file mode 100644 index 00000000000..e45039e0fef --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.java @@ -0,0 +1,23 @@ +public static void main(String[] args) { + { + Browser browser = new Browser(); + browser.loadURL("https://example.com"); + // no further calls + // BAD: The browser ignores any certificate error by default! + } + + { + Browser browser = new Browser(); + browser.setLoadHandler(new LoadHandler() { + public boolean onLoad(LoadParams params) { + return true; + } + + public boolean onCertificateError(CertificateErrorParams params){ + return true; // GOOD: This means that loading will be cancelled on certificate errors + } + }); // GOOD: A secure `LoadHandler` is used. + browser.loadURL("https://example.com"); + + } +} \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp new file mode 100644 index 00000000000..1d9588652c2 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp @@ -0,0 +1,31 @@ + + + + +

    JXBrowser is a Java library that allows to embed the Chromium browser inside Java applications. +The version 6.x.x by default ignores any HTTPS certificate errors thereby allowing man-in-the-middle attacks. +

    +
    + + +

    Do either of these: +

  • Update to version 7.x.x as it now correctly rejects certificate errors by default.
  • +
  • Add a custom implementation of the LoadHandler interface whose onCertificateError method always returns true indicating that loading should be cancelled. +Then use the setLoadHandler method with your custom LoadHandler on every Browser you use.
  • +

    +
    + + +

    The following two examples show two ways of using a Browser. In the 'BAD' case, +all certificate errors are ignored. In the 'GOOD' case, certificate errors are rejected.

    + +
    + + +
  • Teamdev: + +Javadoc for the LoadHandler#onCertificateError method.
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql new file mode 100644 index 00000000000..6e7fe37e668 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql @@ -0,0 +1,73 @@ +/** + * @name JXBrowser with disabled certificate validation + * @description Insecure configuration of JXBrowser disables certificate validation making the app vulnerable to man-in-the-middle attacks. + * @kind problem + * @id java/jxbrowser/disabled-certificate-validation + * @tags security + * external/cwe-295 + */ + +import java +import semmle.code.java.security.Encryption +import semmle.code.java.dataflow.TaintTracking + +/* + * This query is version specific to JXBrowser 6.x.x. The version is indirectly detected. + * In version 6.x.x the `Browser` class is in a different package compared to version 7.x.x. + */ + +/** The `com.teamdev.jxbrowser.chromium.Browser` class. */ +private class JXBrowser extends RefType { + JXBrowser() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "Browser") } +} + +/** The `setLoadHandler` method on the `com.teamdev.jxbrowser.chromium.Browser` class. */ +private class JXBrowserSetLoadHandler extends Method { + JXBrowserSetLoadHandler() { + this.hasName("setLoadHandler") and this.getDeclaringType() instanceof JXBrowser + } +} + +/** The `com.teamdev.jxbrowser.chromium.LoadHandler` interface. */ +private class JXBrowserLoadHandler extends RefType { + JXBrowserLoadHandler() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "LoadHandler") } +} + +private predicate isOnCertificateErrorMethodSafe(Method m) { + forex(ReturnStmt rs | rs.getEnclosingCallable() = m | + rs.getResult().(CompileTimeConstantExpr).getBooleanValue() = true + ) +} + +/** A class that securely implements the `com.teamdev.jxbrowser.chromium.LoadHandler` interface. */ +private class JXBrowserSafeLoadHandler extends RefType { + JXBrowserSafeLoadHandler() { + this.getASupertype() instanceof JXBrowserLoadHandler and + exists(Method m | m.hasName("onCertificateError") and m.getDeclaringType() = this | + isOnCertificateErrorMethodSafe(m) + ) + } +} + +private class JXBrowserTaintTracking extends TaintTracking::Configuration { + JXBrowserTaintTracking() { this = "JXBrowserTaintTracking" } + + override predicate isSource(DataFlow::Node src) { + exists(ClassInstanceExpr newJXBrowser | newJXBrowser.getConstructedType() instanceof JXBrowser | + newJXBrowser = src.asExpr() + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | ma.getMethod() instanceof JXBrowserSetLoadHandler | + ma.getArgument(0).getType() instanceof JXBrowserSafeLoadHandler and + ma.getQualifier() = sink.asExpr() + ) + } +} + +from JXBrowserTaintTracking cfg, DataFlow::Node src +where + cfg.isSource(src) and + not cfg.hasFlow(src, _) +select src, "This JXBrowser instance allows man-in-the-middle attacks." From b30872806dc631f53638f99fc2499fff012c57d8 Mon Sep 17 00:00:00 2001 From: intrigus Date: Tue, 12 Jan 2021 14:49:12 +0100 Subject: [PATCH 005/429] Java: Add tests and test stubs. --- .../JXBrowserWithoutCertValidation.expected | 1 + .../JXBrowserWithoutCertValidation.java | 36 +++++++++++++++++++ .../JXBrowserWithoutCertValidation.qlref | 1 + .../query-tests/security/CWE-295/options | 1 + .../teamdev/jxbrowser/chromium/Browser.java | 9 +++++ .../chromium/CertificateErrorParams.java | 5 +++ .../jxbrowser/chromium/LoadHandler.java | 7 ++++ .../jxbrowser/chromium/LoadParams.java | 5 +++ 8 files changed, 65 insertions(+) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/options create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/Browser.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadHandler.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadParams.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected new file mode 100644 index 00000000000..00d43d1e8b7 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected @@ -0,0 +1 @@ +| JXBrowserWithoutCertValidation.java:17:27:17:39 | new Browser(...) | This JXBrowser instance allows man-in-the-middle attacks. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java new file mode 100644 index 00000000000..97fc8e8770f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java @@ -0,0 +1,36 @@ +import com.teamdev.jxbrowser.chromium.Browser; +import com.teamdev.jxbrowser.chromium.LoadHandler; +import com.teamdev.jxbrowser.chromium.LoadParams; +import com.teamdev.jxbrowser.chromium.CertificateErrorParams; + +public class JXBrowserWithoutCertValidation { + + public static void main(String[] args) { + + badUsage(); + + goodUsage(); + + } + + private static void badUsage() { + Browser browser = new Browser(); + browser.loadURL("https://example.com"); + // no further calls + // BAD: The browser ignores any certificate error by default! + } + + private static void goodUsage() { + Browser browser = new Browser(); + browser.setLoadHandler(new LoadHandler() { + public boolean onLoad(LoadParams params) { + return true; + } + + public boolean onCertificateError(CertificateErrorParams params) { + return true; // GOOD: This means that loading will be cancelled on certificate errors + } + }); // GOOD: A secure `LoadHandler` is used. + browser.loadURL("https://example.com"); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref new file mode 100644 index 00000000000..ab2a3f14bb9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/options b/java/ql/test/experimental/query-tests/security/CWE-295/options new file mode 100644 index 00000000000..770bbcd38e6 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/options @@ -0,0 +1 @@ + //semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jxbrowser-6.23.1 \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/Browser.java b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/Browser.java new file mode 100644 index 00000000000..327a4b4ecd8 --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/Browser.java @@ -0,0 +1,9 @@ +package com.teamdev.jxbrowser.chromium; + +public class Browser extends java.lang.Object { + public void setLoadHandler(LoadHandler handler) { + } + + public void loadURL(String url) { + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java new file mode 100644 index 00000000000..904b98a6c51 --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java @@ -0,0 +1,5 @@ +package com.teamdev.jxbrowser.chromium; + +public final class CertificateErrorParams extends Object { + +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadHandler.java b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadHandler.java new file mode 100644 index 00000000000..a628d88439c --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadHandler.java @@ -0,0 +1,7 @@ +package com.teamdev.jxbrowser.chromium; + +public interface LoadHandler { + boolean onCertificateError(CertificateErrorParams params); + + boolean onLoad(LoadParams params); +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadParams.java b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadParams.java new file mode 100644 index 00000000000..213e54f1dbc --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.23.1/com/teamdev/jxbrowser/chromium/LoadParams.java @@ -0,0 +1,5 @@ +package com.teamdev.jxbrowser.chromium; + +public final class LoadParams extends Object { + +} \ No newline at end of file From 1ebc9f4d9399b9ec0394d9bc810bef481194d7a1 Mon Sep 17 00:00:00 2001 From: intrigus Date: Tue, 12 Jan 2021 22:39:08 +0100 Subject: [PATCH 006/429] Java: Only detect JxBrowser < 6.24 --- .../CWE/CWE-295/JXBrowserWithoutCertValidation.ql | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql index 6e7fe37e668..ab74c78d1e7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql @@ -12,10 +12,18 @@ import semmle.code.java.security.Encryption import semmle.code.java.dataflow.TaintTracking /* - * This query is version specific to JXBrowser 6.x.x. The version is indirectly detected. + * This query is version specific to JXBrowser < 6.24. The version is indirectly detected. * In version 6.x.x the `Browser` class is in a different package compared to version 7.x.x. */ +/** + * Holds if a safe JXBrowser 6.x.x version is used, such as version 6.24. + * This is detected by the the presence of the `addBoundsListener` in the `Browser` class. + */ +private predicate isSafeJXBrowserVersion() { + exists(Method m | m.getDeclaringType() instanceof JXBrowser | m.hasName("addBoundsListener")) +} + /** The `com.teamdev.jxbrowser.chromium.Browser` class. */ private class JXBrowser extends RefType { JXBrowser() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "Browser") } @@ -69,5 +77,6 @@ private class JXBrowserTaintTracking extends TaintTracking::Configuration { from JXBrowserTaintTracking cfg, DataFlow::Node src where cfg.isSource(src) and - not cfg.hasFlow(src, _) + not cfg.hasFlow(src, _) and + not isSafeJXBrowserVersion() select src, "This JXBrowser instance allows man-in-the-middle attacks." From 5b3086a93a07313d79520a24c36d9b45992fd2d1 Mon Sep 17 00:00:00 2001 From: intrigus Date: Tue, 12 Jan 2021 22:43:41 +0100 Subject: [PATCH 007/429] Java: Fix capitalization of JxBrowser --- ...va => JxBrowserWithoutCertValidation.java} | 0 ...p => JxBrowserWithoutCertValidation.qhelp} | 12 ++--- ...n.ql => JxBrowserWithoutCertValidation.ql} | 50 +++++++++---------- .../JXBrowserWithoutCertValidation.expected | 1 - .../JXBrowserWithoutCertValidation.qlref | 1 - .../JxBrowserWithoutCertValidation.expected | 1 + ...va => JxBrowserWithoutCertValidation.java} | 2 +- .../JxBrowserWithoutCertValidation.qlref | 1 + 8 files changed, 34 insertions(+), 34 deletions(-) rename java/ql/src/experimental/Security/CWE/CWE-295/{JXBrowserWithoutCertValidation.java => JxBrowserWithoutCertValidation.java} (100%) rename java/ql/src/experimental/Security/CWE/CWE-295/{JXBrowserWithoutCertValidation.qhelp => JxBrowserWithoutCertValidation.qhelp} (58%) rename java/ql/src/experimental/Security/CWE/CWE-295/{JXBrowserWithoutCertValidation.ql => JxBrowserWithoutCertValidation.ql} (54%) delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected rename java/ql/test/experimental/query-tests/security/CWE-295/{JXBrowserWithoutCertValidation.java => JxBrowserWithoutCertValidation.java} (95%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.java b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.java similarity index 100% rename from java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.java rename to java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp similarity index 58% rename from java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp index 1d9588652c2..27d10c15223 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp @@ -4,14 +4,14 @@ -

    JXBrowser is a Java library that allows to embed the Chromium browser inside Java applications. -The version 6.x.x by default ignores any HTTPS certificate errors thereby allowing man-in-the-middle attacks. +

    JxBrowser is a Java library that allows to embed the Chromium browser inside Java applications. +Versions smaller than 6.24 by default ignore any HTTPS certificate errors thereby allowing man-in-the-middle attacks.

    Do either of these: -

  • Update to version 7.x.x as it now correctly rejects certificate errors by default.
  • +
  • Update to version 6.24 or 7.x.x as these correctly reject certificate errors by default.
  • Add a custom implementation of the LoadHandler interface whose onCertificateError method always returns true indicating that loading should be cancelled. Then use the setLoadHandler method with your custom LoadHandler on every Browser you use.
  • @@ -20,12 +20,12 @@ Then use the setLoadHandler method with your custom LoadHandl

    The following two examples show two ways of using a Browser. In the 'BAD' case, all certificate errors are ignored. In the 'GOOD' case, certificate errors are rejected.

    - +
  • Teamdev: - -Javadoc for the LoadHandler#onCertificateError method.
  • + +Changelog of JxBrowser 6.24.
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql similarity index 54% rename from java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql rename to java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql index ab74c78d1e7..0de4290a44e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql @@ -1,6 +1,6 @@ /** - * @name JXBrowser with disabled certificate validation - * @description Insecure configuration of JXBrowser disables certificate validation making the app vulnerable to man-in-the-middle attacks. + * @name JxBrowser with disabled certificate validation + * @description Insecure configuration of JxBrowser disables certificate validation making the app vulnerable to man-in-the-middle attacks. * @kind problem * @id java/jxbrowser/disabled-certificate-validation * @tags security @@ -12,33 +12,33 @@ import semmle.code.java.security.Encryption import semmle.code.java.dataflow.TaintTracking /* - * This query is version specific to JXBrowser < 6.24. The version is indirectly detected. + * This query is version specific to JxBrowser < 6.24. The version is indirectly detected. * In version 6.x.x the `Browser` class is in a different package compared to version 7.x.x. */ /** - * Holds if a safe JXBrowser 6.x.x version is used, such as version 6.24. + * Holds if a safe JxBrowser 6.x.x version is used, such as version 6.24. * This is detected by the the presence of the `addBoundsListener` in the `Browser` class. */ -private predicate isSafeJXBrowserVersion() { - exists(Method m | m.getDeclaringType() instanceof JXBrowser | m.hasName("addBoundsListener")) +private predicate isSafeJxBrowserVersion() { + exists(Method m | m.getDeclaringType() instanceof JxBrowser | m.hasName("addBoundsListener")) } /** The `com.teamdev.jxbrowser.chromium.Browser` class. */ -private class JXBrowser extends RefType { - JXBrowser() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "Browser") } +private class JxBrowser extends RefType { + JxBrowser() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "Browser") } } /** The `setLoadHandler` method on the `com.teamdev.jxbrowser.chromium.Browser` class. */ -private class JXBrowserSetLoadHandler extends Method { - JXBrowserSetLoadHandler() { - this.hasName("setLoadHandler") and this.getDeclaringType() instanceof JXBrowser +private class JxBrowserSetLoadHandler extends Method { + JxBrowserSetLoadHandler() { + this.hasName("setLoadHandler") and this.getDeclaringType() instanceof JxBrowser } } /** The `com.teamdev.jxbrowser.chromium.LoadHandler` interface. */ -private class JXBrowserLoadHandler extends RefType { - JXBrowserLoadHandler() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "LoadHandler") } +private class JxBrowserLoadHandler extends RefType { + JxBrowserLoadHandler() { this.hasQualifiedName("com.teamdev.jxbrowser.chromium", "LoadHandler") } } private predicate isOnCertificateErrorMethodSafe(Method m) { @@ -48,35 +48,35 @@ private predicate isOnCertificateErrorMethodSafe(Method m) { } /** A class that securely implements the `com.teamdev.jxbrowser.chromium.LoadHandler` interface. */ -private class JXBrowserSafeLoadHandler extends RefType { - JXBrowserSafeLoadHandler() { - this.getASupertype() instanceof JXBrowserLoadHandler and +private class JxBrowserSafeLoadHandler extends RefType { + JxBrowserSafeLoadHandler() { + this.getASupertype() instanceof JxBrowserLoadHandler and exists(Method m | m.hasName("onCertificateError") and m.getDeclaringType() = this | isOnCertificateErrorMethodSafe(m) ) } } -private class JXBrowserTaintTracking extends TaintTracking::Configuration { - JXBrowserTaintTracking() { this = "JXBrowserTaintTracking" } +private class JxBrowserTaintTracking extends TaintTracking::Configuration { + JxBrowserTaintTracking() { this = "JxBrowserTaintTracking" } override predicate isSource(DataFlow::Node src) { - exists(ClassInstanceExpr newJXBrowser | newJXBrowser.getConstructedType() instanceof JXBrowser | - newJXBrowser = src.asExpr() + exists(ClassInstanceExpr newJxBrowser | newJxBrowser.getConstructedType() instanceof JxBrowser | + newJxBrowser = src.asExpr() ) } override predicate isSink(DataFlow::Node sink) { - exists(MethodAccess ma | ma.getMethod() instanceof JXBrowserSetLoadHandler | - ma.getArgument(0).getType() instanceof JXBrowserSafeLoadHandler and + exists(MethodAccess ma | ma.getMethod() instanceof JxBrowserSetLoadHandler | + ma.getArgument(0).getType() instanceof JxBrowserSafeLoadHandler and ma.getQualifier() = sink.asExpr() ) } } -from JXBrowserTaintTracking cfg, DataFlow::Node src +from JxBrowserTaintTracking cfg, DataFlow::Node src where cfg.isSource(src) and not cfg.hasFlow(src, _) and - not isSafeJXBrowserVersion() -select src, "This JXBrowser instance allows man-in-the-middle attacks." + not isSafeJxBrowserVersion() +select src, "This JxBrowser instance allows man-in-the-middle attacks." diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected deleted file mode 100644 index 00d43d1e8b7..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.expected +++ /dev/null @@ -1 +0,0 @@ -| JXBrowserWithoutCertValidation.java:17:27:17:39 | new Browser(...) | This JXBrowser instance allows man-in-the-middle attacks. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref deleted file mode 100644 index ab2a3f14bb9..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-295/JXBrowserWithoutCertValidation.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected new file mode 100644 index 00000000000..121de8759ac --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected @@ -0,0 +1 @@ +| JxBrowserWithoutCertValidation.java:17:27:17:39 | new Browser(...) | This JxBrowser instance allows man-in-the-middle attacks. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.java similarity index 95% rename from java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java rename to java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.java index 97fc8e8770f..b7e2710842f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/JXBrowserWithoutCertValidation.java +++ b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.java @@ -3,7 +3,7 @@ import com.teamdev.jxbrowser.chromium.LoadHandler; import com.teamdev.jxbrowser.chromium.LoadParams; import com.teamdev.jxbrowser.chromium.CertificateErrorParams; -public class JXBrowserWithoutCertValidation { +public class JxBrowserWithoutCertValidation { public static void main(String[] args) { diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.qlref new file mode 100644 index 00000000000..cab6f2a4962 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql From babe744a3011a4f7e2216ff5bd95bed241dd4984 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 13 Jan 2021 03:49:08 +0000 Subject: [PATCH 008/429] Add SECURITY_PROTOCOL check --- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 30 +++++++++++++++---- .../CWE-522/InsecureLdapAuth.expected | 14 ++++----- .../security/CWE-522/InsecureLdapAuth.java | 15 ++++++++++ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 37b3057fb2f..1cebfe8bad3 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -89,22 +89,36 @@ predicate isProviderUrlSetter(MethodAccess ma) { } /** - * Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`. + * Holds if `ma` sets `fieldValue` with attribute name `fieldName` to `envValue` in some `Hashtable`. */ -predicate isSimpleAuthEnv(MethodAccess ma) { +bindingset[fieldName, fieldValue, envValue] +predicate hasEnvWithValue(MethodAccess ma, string fieldName, string fieldValue, string envValue) { ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and ( - ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = - "java.naming.security.authentication" + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = fieldValue or exists(Field f | ma.getArgument(0) = f.getAnAccess() and - f.hasName("SECURITY_AUTHENTICATION") and + f.hasName(fieldName) and f.getDeclaringType() instanceof TypeNamingContext ) ) and - ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = "simple" + ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue +} + +/** + * Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`. + */ +predicate isSimpleAuthEnv(MethodAccess ma) { + hasEnvWithValue(ma, "SECURITY_AUTHENTICATION", "java.naming.security.authentication", "simple") +} + +/** + * Holds if `ma` sets `java.naming.security.protocol` (also known as `Context.SECURITY_PROTOCOL`) to `ssl` in some `Hashtable`. + */ +predicate isSSLEnv(MethodAccess ma) { + hasEnvWithValue(ma, "SECURITY_PROTOCOL", "java.naming.security.protocol", "ssl") } /** @@ -124,6 +138,10 @@ class LdapAuthFlowConfig extends TaintTracking::Configuration { exists(MethodAccess sma | sma.getQualifier() = pma.getQualifier().(VarAccess).getVariable().getAnAccess() and isSimpleAuthEnv(sma) + ) and + not exists(MethodAccess sma | + sma.getQualifier() = pma.getQualifier().(VarAccess).getVariable().getAnAccess() and + isSSLEnv(sma) ) ) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected index c34c8966e0d..745fd9c1b75 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected @@ -1,19 +1,19 @@ edges | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | -| InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | -| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:47:100:53 | ldapUrl | +| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:41:100:47 | ldapUrl | +| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:115:47:115:53 | ldapUrl | nodes | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | semmle.label | ldapUrl | | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | semmle.label | ... + ... : String | | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | semmle.label | ldapUrl | -| InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:85:41:85:47 | ldapUrl | semmle.label | ldapUrl | | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:100:47:100:53 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:100:41:100:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | +| InsecureLdapAuth.java:115:47:115:53 | ldapUrl | semmle.label | ldapUrl | #select | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" | LDAP connection string | | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:25:20:25:39 | ... + ... | LDAP connection string | -| InsecureLdapAuth.java:85:41:85:47 | ldapUrl | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:85:41:85:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:81:20:81:50 | "ldap://ad.your-server.com:389" | LDAP connection string | -| InsecureLdapAuth.java:100:47:100:53 | ldapUrl | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:47:100:53 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:100:41:100:47 | ldapUrl | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:41:100:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:115:47:115:53 | ldapUrl | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:115:47:115:53 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" | LDAP connection string | diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java index cc16047ebf2..4052557d8b0 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java @@ -48,6 +48,21 @@ public class InsecureLdapAuth { DirContext dirContext = new InitialDirContext(environment); } + // GOOD - Test LDAP authentication over SSL. + public void testSslLdapAuth2(String ldapUserName, String password) { + String ldapUrl = "ldap://ad.your-server.com:636"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + environment.put(Context.REFERRAL, "follow"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); + environment.put(Context.SECURITY_CREDENTIALS, password); + environment.put(Context.SECURITY_PROTOCOL, "ssl"); + DirContext dirContext = new InitialDirContext(environment); + } + // GOOD - Test LDAP authentication with SASL authentication. public void testSaslLdapAuth(String ldapUserName, String password) { String ldapUrl = "ldap://ad.your-server.com:389"; From f3b8fe2e2ed760301bbf417e94d2738f2d0d5b06 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 13 Jan 2021 13:42:35 +0100 Subject: [PATCH 009/429] Java: Add Member.hasQualifiedName. --- java/ql/src/semmle/code/java/Member.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/java/ql/src/semmle/code/java/Member.qll b/java/ql/src/semmle/code/java/Member.qll index e9d4fe82978..a0e988bd386 100755 --- a/java/ql/src/semmle/code/java/Member.qll +++ b/java/ql/src/semmle/code/java/Member.qll @@ -23,6 +23,14 @@ class Member extends Element, Annotatable, Modifiable, @member { /** Gets the qualified name of this member. */ string getQualifiedName() { result = getDeclaringType().getName() + "." + getName() } + /** + * Holds if this member has the specified name and is declared in the + * specified package and type. + */ + predicate hasQualifiedName(string package, string type, string name) { + this.getDeclaringType().hasQualifiedName(package, type) and this.hasName(name) + } + /** Holds if this member is package protected, that is, neither public nor private nor protected. */ predicate isPackageProtected() { not isPrivate() and From b8076481bf353caf6b3a68348144114ebb1d96d7 Mon Sep 17 00:00:00 2001 From: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> Date: Wed, 13 Jan 2021 20:32:23 +0100 Subject: [PATCH 010/429] Java: Suggestions from Review --- .../Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql index 0de4290a44e..6aee64ed010 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql @@ -79,4 +79,4 @@ where cfg.isSource(src) and not cfg.hasFlow(src, _) and not isSafeJxBrowserVersion() -select src, "This JxBrowser instance allows man-in-the-middle attacks." +select src, "This JxBrowser instance may not check HTTPS certificates." From e5a703e49c3fe53aeda8e6ecb9d3766df7683124 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 15 Jan 2021 04:05:11 +0000 Subject: [PATCH 011/429] Revamp the query --- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 109 +++++++++++++++--- .../CWE-522/InsecureLdapAuth.expected | 79 +++++++++++-- .../security/CWE-522/InsecureLdapAuth.java | 33 ++++++ 3 files changed, 190 insertions(+), 31 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 1cebfe8bad3..1a38f74092b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -110,7 +110,7 @@ predicate hasEnvWithValue(MethodAccess ma, string fieldName, string fieldValue, /** * Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`. */ -predicate isSimpleAuthEnv(MethodAccess ma) { +predicate isBasicAuthEnv(MethodAccess ma) { hasEnvWithValue(ma, "SECURITY_AUTHENTICATION", "java.naming.security.authentication", "simple") } @@ -122,32 +122,103 @@ predicate isSSLEnv(MethodAccess ma) { } /** - * A taint-tracking configuration for cleartext credentials in LDAP authentication. + * A taint-tracking configuration for `ldap://` URL in LDAP authentication. */ -class LdapAuthFlowConfig extends TaintTracking::Configuration { - LdapAuthFlowConfig() { this = "InsecureLdapAuth:LdapAuthFlowConfig" } +class InsecureUrlFlowConfig extends TaintTracking::Configuration { + InsecureUrlFlowConfig() { this = "InsecureLdapAuth:InsecureUrlFlowConfig" } - /** Source of non-private LDAP connection string */ + /** Source of `ldap://` connection string. */ override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof InsecureLdapUrl } - /** Sink of provider URL with simple authentication */ + /** Sink of directory context creation. */ override predicate isSink(DataFlow::Node sink) { - exists(MethodAccess pma | - sink.asExpr() = pma.getArgument(1) and - isProviderUrlSetter(pma) and - exists(MethodAccess sma | - sma.getQualifier() = pma.getQualifier().(VarAccess).getVariable().getAnAccess() and - isSimpleAuthEnv(sma) - ) and - not exists(MethodAccess sma | - sma.getQualifier() = pma.getQualifier().(VarAccess).getVariable().getAnAccess() and - isSSLEnv(sma) - ) + exists(ConstructorCall cc | + cc.getConstructedType().getASupertype*() instanceof TypeDirContext and + sink.asExpr() = cc.getArgument(0) + ) + } + + /** Method call of `env.put()`. */ + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(MethodAccess ma | + pred.asExpr() = ma.getArgument(1) and + isProviderUrlSetter(ma) and + succ.asExpr() = ma.getQualifier() ) } } -from DataFlow::PathNode source, DataFlow::PathNode sink, LdapAuthFlowConfig config -where config.hasFlowPath(source, sink) +/** + * A taint-tracking configuration for `simple` basic-authentication in LDAP configuration. + */ +class BasicAuthFlowConfig extends TaintTracking::Configuration { + BasicAuthFlowConfig() { this = "InsecureLdapAuth:BasicAuthFlowConfig" } + + /** Source of `simple` configuration. */ + override predicate isSource(DataFlow::Node src) { + src.asExpr().(CompileTimeConstantExpr).getStringValue() = "simple" + } + + /** Sink of directory context creation. */ + override predicate isSink(DataFlow::Node sink) { + exists(ConstructorCall cc | + cc.getConstructedType().getASupertype*() instanceof TypeDirContext and + sink.asExpr() = cc.getArgument(0) + ) + } + + /** Method call of `env.put()`. */ + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(MethodAccess ma | + pred.asExpr() = ma.getArgument(1) and + isBasicAuthEnv(ma) and + succ.asExpr() = ma.getQualifier() + ) + } +} + +/** + * A taint-tracking configuration for `ssl` configuration in LDAP authentication. + */ +class SSLFlowConfig extends TaintTracking::Configuration { + SSLFlowConfig() { this = "InsecureLdapAuth:SSLFlowConfig" } + + /** Source of `ssl` configuration. */ + override predicate isSource(DataFlow::Node src) { + src.asExpr().(CompileTimeConstantExpr).getStringValue() = "ssl" + } + + /** Sink of directory context creation. */ + override predicate isSink(DataFlow::Node sink) { + exists(ConstructorCall cc | + cc.getConstructedType().getASupertype*() instanceof TypeDirContext and + sink.asExpr() = cc.getArgument(0) + ) + } + + /** Method call of `env.put()`. */ + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(MethodAccess ma | + pred.asExpr() = ma.getArgument(1) and + isSSLEnv(ma) and + succ.asExpr() = ma.getQualifier() + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureUrlFlowConfig config, VarAccess va +where + config.hasFlowPath(source, sink) and + sink.getNode().asExpr() = va and + exists(BasicAuthFlowConfig bc, DataFlow::PathNode source2, DataFlow::PathNode sink2 | + bc.hasFlowPath(source2, sink2) and + source2.getNode().asExpr().(CompileTimeConstantExpr).getStringValue() = "simple" and + sink2.getNode().asExpr() = va + ) and + not exists(SSLFlowConfig sc, DataFlow::PathNode source3, DataFlow::PathNode sink3 | + sc.hasFlowPath(source3, sink3) and + source3.getNode().asExpr().(CompileTimeConstantExpr).getStringValue() = "ssl" and + sink3.getNode().asExpr() = va.getVariable().getAnAccess() + ) select sink.getNode(), source, sink, "Insecure LDAP authentication from $@.", source.getNode(), "LDAP connection string" diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected index 745fd9c1b75..1af36e67d05 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected @@ -1,19 +1,74 @@ edges -| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | -| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | -| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:41:100:47 | ldapUrl | -| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:115:47:115:53 | ldapUrl | +| InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:20:49:20:59 | environment | +| InsecureLdapAuth.java:17:52:17:59 | "simple" : String | InsecureLdapAuth.java:20:49:20:59 | environment | +| InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:34:49:34:59 | environment | +| InsecureLdapAuth.java:31:52:31:59 | "simple" : String | InsecureLdapAuth.java:34:49:34:59 | environment | +| InsecureLdapAuth.java:45:52:45:59 | "simple" : String | InsecureLdapAuth.java:48:49:48:59 | environment | +| InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | InsecureLdapAuth.java:63:49:63:59 | environment | +| InsecureLdapAuth.java:59:52:59:59 | "simple" : String | InsecureLdapAuth.java:63:49:63:59 | environment | +| InsecureLdapAuth.java:62:46:62:50 | "ssl" : String | InsecureLdapAuth.java:63:49:63:59 | environment | +| InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:77:49:77:59 | environment | +| InsecureLdapAuth.java:88:52:88:59 | "simple" : String | InsecureLdapAuth.java:91:49:91:59 | environment | +| InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:105:59:105:69 | environment | +| InsecureLdapAuth.java:102:52:102:59 | "simple" : String | InsecureLdapAuth.java:105:59:105:69 | environment | +| InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:120:49:120:59 | environment | +| InsecureLdapAuth.java:117:58:117:65 | "simple" : String | InsecureLdapAuth.java:120:49:120:59 | environment | +| InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | +| InsecureLdapAuth.java:124:38:124:42 | "ssl" : String | InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | +| InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | +| InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | +| InsecureLdapAuth.java:128:44:128:51 | "simple" : String | InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | +| InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | InsecureLdapAuth.java:142:50:142:60 | environment | +| InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | InsecureLdapAuth.java:142:50:142:60 | environment | +| InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | InsecureLdapAuth.java:142:50:142:60 | environment | +| InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | InsecureLdapAuth.java:153:50:153:60 | environment | +| InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | InsecureLdapAuth.java:153:50:153:60 | environment | nodes | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:15:41:15:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:17:52:17:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:20:49:20:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:20:49:20:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | semmle.label | ... + ... : String | -| InsecureLdapAuth.java:29:41:29:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:31:52:31:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:34:49:34:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:34:49:34:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:45:52:45:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:48:49:48:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | semmle.label | "ldap://ad.your-server.com:636" : String | +| InsecureLdapAuth.java:59:52:59:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:62:46:62:50 | "ssl" : String | semmle.label | "ssl" : String | +| InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | +| InsecureLdapAuth.java:77:49:77:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:88:52:88:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:91:49:91:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:100:41:100:47 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:102:52:102:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:105:59:105:69 | environment | semmle.label | environment | +| InsecureLdapAuth.java:105:59:105:69 | environment | semmle.label | environment | | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:115:47:115:53 | ldapUrl | semmle.label | ldapUrl | +| InsecureLdapAuth.java:117:58:117:65 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:120:49:120:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:120:49:120:59 | environment | semmle.label | environment | +| InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | semmle.label | env [post update] : Hashtable | +| InsecureLdapAuth.java:124:38:124:42 | "ssl" : String | semmle.label | "ssl" : String | +| InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | semmle.label | env [post update] : Hashtable | +| InsecureLdapAuth.java:128:44:128:51 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | semmle.label | ... + ... : String | +| InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | +| InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | +| InsecureLdapAuth.java:142:50:142:60 | environment | semmle.label | environment | +| InsecureLdapAuth.java:142:50:142:60 | environment | semmle.label | environment | +| InsecureLdapAuth.java:142:50:142:60 | environment | semmle.label | environment | +| InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | semmle.label | ... + ... : String | +| InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | +| InsecureLdapAuth.java:153:50:153:60 | environment | semmle.label | environment | +| InsecureLdapAuth.java:153:50:153:60 | environment | semmle.label | environment | #select -| InsecureLdapAuth.java:15:41:15:47 | ldapUrl | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:15:41:15:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" | LDAP connection string | -| InsecureLdapAuth.java:29:41:29:47 | ldapUrl | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:29:41:29:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:25:20:25:39 | ... + ... | LDAP connection string | -| InsecureLdapAuth.java:100:41:100:47 | ldapUrl | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:100:41:100:47 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" | LDAP connection string | -| InsecureLdapAuth.java:115:47:115:53 | ldapUrl | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:115:47:115:53 | ldapUrl | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:20:49:20:59 | environment | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:20:49:20:59 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:34:49:34:59 | environment | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:34:49:34:59 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:25:20:25:39 | ... + ... | LDAP connection string | +| InsecureLdapAuth.java:105:59:105:69 | environment | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:105:59:105:69 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:120:49:120:59 | environment | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:120:49:120:59 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" | LDAP connection string | +| InsecureLdapAuth.java:153:50:153:60 | environment | InsecureLdapAuth.java:147:20:147:39 | ... + ... : String | InsecureLdapAuth.java:153:50:153:60 | environment | Insecure LDAP authentication from $@. | InsecureLdapAuth.java:147:20:147:39 | ... + ... | LDAP connection string | diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java index 4052557d8b0..14142d31b21 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java @@ -119,4 +119,37 @@ public class InsecureLdapAuth { environment.put("java.naming.security.credentials", password); DirContext dirContext = new InitialDirContext(environment); } + + private void setSSL(Hashtable env) { + env.put(Context.SECURITY_PROTOCOL, "ssl"); + } + + private void setBasicAuth(Hashtable env, String ldapUserName, String password) { + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, ldapUserName); + env.put(Context.SECURITY_CREDENTIALS, password); + } + + // GOOD - Test LDAP authentication with `ssl` configuration and basic authentication. + public void testCleartextLdapAuth5(String ldapUserName, String password, String serverName) { + String ldapUrl = "ldap://"+serverName+":389"; + Hashtable environment = new Hashtable(); + setSSL(environment); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + setBasicAuth(environment, ldapUserName, password); + DirContext dirContext = new InitialLdapContext(environment, null); + } + + // BAD - Test LDAP authentication with basic authentication. + public void testCleartextLdapAuth6(String ldapUserName, String password, String serverName) { + String ldapUrl = "ldap://"+serverName+":389"; + Hashtable environment = new Hashtable(); + environment.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + environment.put(Context.PROVIDER_URL, ldapUrl); + setBasicAuth(environment, ldapUserName, password); + DirContext dirContext = new InitialLdapContext(environment, null); + } } From 32c54628f8afc010e4000368d9abdecea6b50f7f Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 15 Jan 2021 12:32:13 +0000 Subject: [PATCH 012/429] Drop fieldName from the function for runtime evaluation --- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 1a38f74092b..602dae21ad7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -91,19 +91,11 @@ predicate isProviderUrlSetter(MethodAccess ma) { /** * Holds if `ma` sets `fieldValue` with attribute name `fieldName` to `envValue` in some `Hashtable`. */ -bindingset[fieldName, fieldValue, envValue] -predicate hasEnvWithValue(MethodAccess ma, string fieldName, string fieldValue, string envValue) { +bindingset[fieldValue, envValue] +predicate hasEnvWithValue(MethodAccess ma, string fieldValue, string envValue) { ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and - ( - ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = fieldValue - or - exists(Field f | - ma.getArgument(0) = f.getAnAccess() and - f.hasName(fieldName) and - f.getDeclaringType() instanceof TypeNamingContext - ) - ) and + ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = fieldValue and ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue } @@ -111,15 +103,13 @@ predicate hasEnvWithValue(MethodAccess ma, string fieldName, string fieldValue, * Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`. */ predicate isBasicAuthEnv(MethodAccess ma) { - hasEnvWithValue(ma, "SECURITY_AUTHENTICATION", "java.naming.security.authentication", "simple") + hasEnvWithValue(ma, "java.naming.security.authentication", "simple") } /** * Holds if `ma` sets `java.naming.security.protocol` (also known as `Context.SECURITY_PROTOCOL`) to `ssl` in some `Hashtable`. */ -predicate isSSLEnv(MethodAccess ma) { - hasEnvWithValue(ma, "SECURITY_PROTOCOL", "java.naming.security.protocol", "ssl") -} +predicate isSSLEnv(MethodAccess ma) { hasEnvWithValue(ma, "java.naming.security.protocol", "ssl") } /** * A taint-tracking configuration for `ldap://` URL in LDAP authentication. From a4cbd7037bd068228bef5448aa11ceeed92d1554 Mon Sep 17 00:00:00 2001 From: intrigus Date: Fri, 15 Jan 2021 17:18:22 +0100 Subject: [PATCH 013/429] Java: Add tests for different versions. Adds a test for version 6.24, because that version is not vulnerable. The other test is for versions < 6.24, because these versions are vulnerable. --- .../JxBrowserWithoutCertValidation.expected | 1 - .../JxBrowserWithoutCertValidation.expected | 1 + .../JxBrowserWithoutCertValidation.qlref | 0 ...xBrowserWithoutCertValidationV6_23_1.java} | 2 +- .../security/CWE-295/jxbrowser-6.23.1/options | 1 + .../JxBrowserWithoutCertValidation.expected | 0 .../JxBrowserWithoutCertValidation.qlref | 1 + .../JxBrowserWithoutCertValidationV6_24.java | 36 +++++++++++++++++++ .../CWE-295/{ => jxbrowser-6.24}/options | 2 +- .../jxbrowser/chromium/BoundsListener.java | 5 +++ .../teamdev/jxbrowser/chromium/Browser.java | 13 +++++++ .../chromium/CertificateErrorParams.java | 5 +++ .../jxbrowser/chromium/LoadHandler.java | 7 ++++ .../jxbrowser/chromium/LoadParams.java | 5 +++ 14 files changed, 76 insertions(+), 3 deletions(-) delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected rename java/ql/test/experimental/query-tests/security/CWE-295/{ => jxbrowser-6.23.1}/JxBrowserWithoutCertValidation.qlref (100%) rename java/ql/test/experimental/query-tests/security/CWE-295/{JxBrowserWithoutCertValidation.java => jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java} (95%) create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/options create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidationV6_24.java rename java/ql/test/experimental/query-tests/security/CWE-295/{ => jxbrowser-6.24}/options (71%) create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/BoundsListener.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/Browser.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadHandler.java create mode 100644 java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadParams.java diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected deleted file mode 100644 index 121de8759ac..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.expected +++ /dev/null @@ -1 +0,0 @@ -| JxBrowserWithoutCertValidation.java:17:27:17:39 | new Browser(...) | This JxBrowser instance allows man-in-the-middle attacks. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected new file mode 100644 index 00000000000..9b611b6cfc9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected @@ -0,0 +1 @@ +| JxBrowserWithoutCertValidationV6_23_1.java:17:27:17:39 | new Browser(...) | This JxBrowser instance allows man-in-the-middle attacks. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.qlref similarity index 100% rename from java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.qlref rename to java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.qlref diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.java b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java similarity index 95% rename from java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.java rename to java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java index b7e2710842f..8f7be261413 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/JxBrowserWithoutCertValidation.java +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidationV6_23_1.java @@ -3,7 +3,7 @@ import com.teamdev.jxbrowser.chromium.LoadHandler; import com.teamdev.jxbrowser.chromium.LoadParams; import com.teamdev.jxbrowser.chromium.CertificateErrorParams; -public class JxBrowserWithoutCertValidation { +public class JxBrowserWithoutCertValidationV6_23_1 { public static void main(String[] args) { diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/options b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/options new file mode 100644 index 00000000000..37339271f9c --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/options @@ -0,0 +1 @@ + //semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/jxbrowser-6.23.1 \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref new file mode 100644 index 00000000000..cab6f2a4962 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidation.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidationV6_24.java b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidationV6_24.java new file mode 100644 index 00000000000..62057fcb8ef --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/JxBrowserWithoutCertValidationV6_24.java @@ -0,0 +1,36 @@ +import com.teamdev.jxbrowser.chromium.Browser; +import com.teamdev.jxbrowser.chromium.LoadHandler; +import com.teamdev.jxbrowser.chromium.LoadParams; +import com.teamdev.jxbrowser.chromium.CertificateErrorParams; + +public class JxBrowserWithoutCertValidationV6_24 { + + public static void main(String[] args) { + + goodUsage(); + + goodUsage2(); + + } + + private static void goodUsage() { + Browser browser = new Browser(); + browser.loadURL("https://example.com"); + // no further calls + // GOOD: On version 6.24 the browser properly validates certificates by default! + } + + private static void goodUsage2() { + Browser browser = new Browser(); + browser.setLoadHandler(new LoadHandler() { + public boolean onLoad(LoadParams params) { + return true; + } + + public boolean onCertificateError(CertificateErrorParams params) { + return true; // GOOD: This means that loading will be cancelled on certificate errors + } + }); // GOOD: A secure `LoadHandler` is used. + browser.loadURL("https://example.com"); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/options b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/options similarity index 71% rename from java/ql/test/experimental/query-tests/security/CWE-295/options rename to java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/options index 770bbcd38e6..f001bf777a2 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/options +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.24/options @@ -1 +1 @@ - //semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/jxbrowser-6.23.1 \ No newline at end of file + //semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/jxbrowser-6.24 \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/BoundsListener.java b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/BoundsListener.java new file mode 100644 index 00000000000..39bb56e0565 --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/BoundsListener.java @@ -0,0 +1,5 @@ +package com.teamdev.jxbrowser.chromium; + +public interface BoundsListener { + +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/Browser.java b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/Browser.java new file mode 100644 index 00000000000..c32656e4228 --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/Browser.java @@ -0,0 +1,13 @@ +package com.teamdev.jxbrowser.chromium; + +public class Browser extends java.lang.Object { + public void setLoadHandler(LoadHandler handler) { + } + + public void loadURL(String url) { + } + + public void addBoundsListener(BoundsListener listener) { + + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java new file mode 100644 index 00000000000..904b98a6c51 --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/CertificateErrorParams.java @@ -0,0 +1,5 @@ +package com.teamdev.jxbrowser.chromium; + +public final class CertificateErrorParams extends Object { + +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadHandler.java b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadHandler.java new file mode 100644 index 00000000000..a628d88439c --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadHandler.java @@ -0,0 +1,7 @@ +package com.teamdev.jxbrowser.chromium; + +public interface LoadHandler { + boolean onCertificateError(CertificateErrorParams params); + + boolean onLoad(LoadParams params); +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadParams.java b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadParams.java new file mode 100644 index 00000000000..213e54f1dbc --- /dev/null +++ b/java/ql/test/experimental/stubs/jxbrowser-6.24/com/teamdev/jxbrowser/chromium/LoadParams.java @@ -0,0 +1,5 @@ +package com.teamdev.jxbrowser.chromium; + +public final class LoadParams extends Object { + +} \ No newline at end of file From efb872ad1e96bcc703394777e80046ab8b043a79 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 14 Jan 2021 19:15:52 +0100 Subject: [PATCH 014/429] Python: Add HttpRedirectResponse concept --- python/ql/src/semmle/python/Concepts.qll | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/python/ql/src/semmle/python/Concepts.qll b/python/ql/src/semmle/python/Concepts.qll index a79eaa2dc55..b81817d7f10 100644 --- a/python/ql/src/semmle/python/Concepts.qll +++ b/python/ql/src/semmle/python/Concepts.qll @@ -473,5 +473,40 @@ module HTTP { } } } + + /** + * A data-flow node that creates a HTTP redirect response on a server. + * + * Note: we don't require that this redirect must be sent to a client (a kind of + * "if a tree falls in a forest and nobody hears it" situation). + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `HttpRedirectResponse::Range` instead. + */ + class HttpRedirectResponse extends HttpResponse { + override HttpRedirectResponse::Range range; + + HttpRedirectResponse() { this = range } + + /** Gets the data-flow node that specifies the location of this HTTP redirect response. */ + DataFlow::Node getRedirectLocation() { result = range.getRedirectLocation() } + } + + /** Provides a class for modeling new HTTP redirect response APIs. */ + module HttpRedirectResponse { + /** + * A data-flow node that creates a HTTP redirect response on a server. + * + * Note: we don't require that this redirect must be sent to a client (a kind of + * "if a tree falls in a forest and nobody hears it" situation). + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `HttpResponse` instead. + */ + abstract class Range extends HTTP::Server::HttpResponse::Range { + /** Gets the data-flow node that specifies the location of this HTTP redirect response. */ + abstract DataFlow::Node getRedirectLocation(); + } + } } } From 501e5106226f4dc8cb287d9db4a099435c41708a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 14:43:25 +0100 Subject: [PATCH 015/429] Python: Add redirect modeling tests (flask/django) --- .../frameworks/django-v1/response_test.py | 30 +++++++++++++++---- .../frameworks/flask/response_test.py | 14 ++++++++- .../test/experimental/meta/ConceptsTest.qll | 25 ++++++++++++++++ 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py index 1713173d026..b36b1e1822c 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py @@ -1,4 +1,4 @@ -from django.http.response import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound +from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, JsonResponse, HttpResponseNotFound # Not an XSS sink, since the Content-Type is not "text/html" # FP reported in https://github.com/github/codeql-python-team/issues/38 @@ -18,15 +18,35 @@ def safe__manual_content_type(request): # XSS FP reported in https://github.com/github/codeql/issues/3466 # Note: This should be an open-redirect sink, but not an XSS sink. def or__redirect(request): - return HttpResponseRedirect(request.GET.get("next")) # $HttpResponse mimetype=text/html + next = request.GET.get("next") + return HttpResponseRedirect(next) # $HttpResponse mimetype=text/html MISSING: HttpRedirectResponse redirectLocation=next -def information_exposure_through_redirect(request, as_kw=False): +def information_exposure_through_redirect(request, as_kw=False, perm_redirect=False): # This is a contrived example, but possible private = "private" + next = request.GET.get("next") if as_kw: - return HttpResponseRedirect(request.GET.get("next"), content=private) # $HttpResponse mimetype=text/html responseBody=private + return HttpResponseRedirect(next, content=private) # $HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next else: - return HttpResponseRedirect(request.GET.get("next"), private) # $HttpResponse mimetype=text/html responseBody=private + return HttpResponseRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next + + +def perm_redirect(request): + private = "private" + next = request.GET.get("next") + return HttpResponsePermanentRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next + + +def redirect_through_normal_response(request): + private = "private" + next = request.GET.get("next") + + resp = HttpResponse() # $ HttpResponse mimetype=text/html + resp.status_code = 302 + resp['Location'] = next # $ MISSING: redirectLocation=next + resp.content = private # $ MISSING: responseBody=private + return resp + # Ensure that simple subclasses are still vuln to XSS def xss__not_found(request): diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py index b067f173882..7c15704f7e3 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py @@ -1,6 +1,6 @@ import json -from flask import Flask, make_response, jsonify, Response, request +from flask import Flask, make_response, jsonify, Response, request, redirect app = Flask(__name__) @@ -172,6 +172,18 @@ def app_response_class(): # $requestHandler # TODO: add tests for setting status code # TODO: add test that manually creates a redirect by setting status code and suitable header. +################################################################################ +# Redirect +################################################################################ + + +@app.route("/redirect-simple") # $routeSetup="/redirect-simple" +def redirect_simple(): # $requestHandler + next = request.args['next'] + resp = redirect(next) # $ MISSING: HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next + return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp + + ################################################################################ diff --git a/python/ql/test/experimental/meta/ConceptsTest.qll b/python/ql/test/experimental/meta/ConceptsTest.qll index 0516fe5dac3..eafcb8b0ef9 100644 --- a/python/ql/test/experimental/meta/ConceptsTest.qll +++ b/python/ql/test/experimental/meta/ConceptsTest.qll @@ -239,6 +239,31 @@ class HttpServerHttpResponseTest extends InlineExpectationsTest { } } +class HttpServerHttpRedirectResponseTest extends InlineExpectationsTest { + HttpServerHttpRedirectResponseTest() { this = "HttpServerHttpRedirectResponseTest" } + + override string getARelevantTag() { result in ["HttpRedirectResponse", "redirectLocation"] } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + exists(location.getFile().getRelativePath()) and + ( + exists(HTTP::Server::HttpRedirectResponse redirect | + location = redirect.getLocation() and + element = redirect.toString() and + value = "" and + tag = "HttpRedirectResponse" + ) + or + exists(HTTP::Server::HttpRedirectResponse redirect | + location = redirect.getLocation() and + element = redirect.toString() and + value = value_from_expr(redirect.getRedirectLocation().asExpr()) and + tag = "redirectLocation" + ) + ) + } +} + class FileSystemAccessTest extends InlineExpectationsTest { FileSystemAccessTest() { this = "FileSystemAccessTest" } From aea974ee0c1372a7872222667f77b22e24263eea Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 14:44:50 +0100 Subject: [PATCH 016/429] Python: Add redirect modeling for Flask --- .../ql/src/semmle/python/frameworks/Flask.qll | 29 ++++++++++++++++++- .../frameworks/flask/response_test.py | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 68f81e32ceb..c49c012f6f0 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -34,7 +34,7 @@ private module FlaskModel { * WARNING: Only holds for a few predefined attributes. */ private DataFlow::Node flask_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in ["request", "make_response", "Response", "views"] and + attr_name in ["request", "make_response", "Response", "views", "redirect"] and ( t.start() and result = DataFlow::importNode("flask" + "." + attr_name) @@ -669,4 +669,31 @@ private module FlaskModel { override string getMimetypeDefault() { result = "text/html" } } + + /** + * A call to the `flask.redirect` function. + * + * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.redirect + */ + private class FlaskRedirectCall extends HTTP::Server::HttpRedirectResponse::Range, + DataFlow::CfgNode { + override CallNode node; + + FlaskRedirectCall() { node.getFunction() = flask_attr("redirect").asCfgNode() } + + override DataFlow::Node getRedirectLocation() { + result.asCfgNode() in [node.getArg(0), node.getArgByName("location")] + } + + override DataFlow::Node getBody() { none() } + + override DataFlow::Node getMimetypeOrContentTypeArg() { none() } + + override string getMimetypeDefault() { + // note that while you're not able to set content yourself, the function will + // actually fill out some default content, that is served with mimetype + // `text/html`. + result = "text/html" + } + } } diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py index 7c15704f7e3..ec2de218c84 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/response_test.py @@ -180,7 +180,7 @@ def app_response_class(): # $requestHandler @app.route("/redirect-simple") # $routeSetup="/redirect-simple" def redirect_simple(): # $requestHandler next = request.args['next'] - resp = redirect(next) # $ MISSING: HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next + resp = redirect(next) # $ HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next return resp # $ SPURIOUS: HttpResponse mimetype=text/html responseBody=resp From ab607b803093fd8a6055b7236c25bdc97fff86e8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 14:45:41 +0100 Subject: [PATCH 017/429] Python: Add redirect modeling for Django --- python/ql/src/semmle/python/frameworks/Django.qll | 14 ++++++++++++-- .../frameworks/django-v1/response_test.py | 8 ++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 674aedec566..4251b515322 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -724,7 +724,8 @@ private module Django { * * Use the predicate `HttpResponseRedirect::instance()` to get references to instances of `django.http.response.HttpResponseRedirect`. */ - abstract class InstanceSource extends HttpResponse::InstanceSource, DataFlow::Node { } + abstract class InstanceSource extends HttpResponse::InstanceSource, + HTTP::Server::HttpRedirectResponse::Range, DataFlow::Node { } /** A direct instantiation of `django.http.response.HttpResponseRedirect`. */ private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { @@ -739,6 +740,10 @@ private module Django { result.asCfgNode() in [node.getArg(1), node.getArgByName("content")] } + override DataFlow::Node getRedirectLocation() { + result.asCfgNode() in [node.getArg(0), node.getArgByName("redirect_to")] + } + // How to support the `headers` argument here? override DataFlow::Node getMimetypeOrContentTypeArg() { none() } @@ -790,7 +795,8 @@ private module Django { * * Use the predicate `HttpResponsePermanentRedirect::instance()` to get references to instances of `django.http.response.HttpResponsePermanentRedirect`. */ - abstract class InstanceSource extends HttpResponse::InstanceSource, DataFlow::Node { } + abstract class InstanceSource extends HttpResponse::InstanceSource, + HTTP::Server::HttpRedirectResponse::Range, DataFlow::Node { } /** A direct instantiation of `django.http.response.HttpResponsePermanentRedirect`. */ private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { @@ -805,6 +811,10 @@ private module Django { result.asCfgNode() in [node.getArg(1), node.getArgByName("content")] } + override DataFlow::Node getRedirectLocation() { + result.asCfgNode() in [node.getArg(0), node.getArgByName("redirect_to")] + } + // How to support the `headers` argument here? override DataFlow::Node getMimetypeOrContentTypeArg() { none() } diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py index b36b1e1822c..69cdd899c8d 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py @@ -19,22 +19,22 @@ def safe__manual_content_type(request): # Note: This should be an open-redirect sink, but not an XSS sink. def or__redirect(request): next = request.GET.get("next") - return HttpResponseRedirect(next) # $HttpResponse mimetype=text/html MISSING: HttpRedirectResponse redirectLocation=next + return HttpResponseRedirect(next) # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next def information_exposure_through_redirect(request, as_kw=False, perm_redirect=False): # This is a contrived example, but possible private = "private" next = request.GET.get("next") if as_kw: - return HttpResponseRedirect(next, content=private) # $HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next + return HttpResponseRedirect(next, content=private) # $HttpResponse mimetype=text/html responseBody=private HttpRedirectResponse redirectLocation=next else: - return HttpResponseRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next + return HttpResponseRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private HttpRedirectResponse redirectLocation=next def perm_redirect(request): private = "private" next = request.GET.get("next") - return HttpResponsePermanentRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private MISSING: HttpRedirectResponse redirectLocation=next + return HttpResponsePermanentRedirect(next, private) # $ HttpResponse mimetype=text/html responseBody=private HttpRedirectResponse redirectLocation=next def redirect_through_normal_response(request): From 9d8925ae6a47aa74edacf14e32f15221d5269e3f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 15:16:55 +0100 Subject: [PATCH 018/429] Python: Extend url-redirect tests Specifically to show how it currently handles prefixing user-input with known constant. I changed test to be Python 3 only since I wanted to use f-string. --- .../Security/CWE-601/UrlRedirect.expected | 45 +++++++++++++ .../test/query-tests/Security/CWE-601/options | 2 +- .../test/query-tests/Security/CWE-601/test.py | 64 ++++++++++++++++++- 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected index 87e3a9b98f1..ec681a905a5 100644 --- a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected @@ -3,5 +3,50 @@ edges | test.py:7:14:7:25 | dict of externally controlled string | test.py:7:14:7:43 | externally controlled string | | test.py:7:14:7:43 | externally controlled string | test.py:8:21:8:26 | externally controlled string | | test.py:7:14:7:43 | externally controlled string | test.py:8:21:8:26 | externally controlled string | +| test.py:30:17:30:28 | dict of externally controlled string | test.py:30:17:30:46 | externally controlled string | +| test.py:30:17:30:28 | dict of externally controlled string | test.py:30:17:30:46 | externally controlled string | +| test.py:30:17:30:46 | externally controlled string | test.py:31:41:31:49 | externally controlled string | +| test.py:30:17:30:46 | externally controlled string | test.py:31:41:31:49 | externally controlled string | +| test.py:31:12:31:50 | externally controlled string | test.py:32:21:32:24 | externally controlled string | +| test.py:31:12:31:50 | externally controlled string | test.py:32:21:32:24 | externally controlled string | +| test.py:31:41:31:49 | externally controlled string | test.py:31:12:31:50 | externally controlled string | +| test.py:31:41:31:49 | externally controlled string | test.py:31:12:31:50 | externally controlled string | +| test.py:37:17:37:28 | dict of externally controlled string | test.py:37:17:37:46 | externally controlled string | +| test.py:37:17:37:28 | dict of externally controlled string | test.py:37:17:37:46 | externally controlled string | +| test.py:37:17:37:46 | externally controlled string | test.py:38:32:38:40 | externally controlled string | +| test.py:37:17:37:46 | externally controlled string | test.py:38:32:38:40 | externally controlled string | +| test.py:38:12:38:42 | externally controlled string | test.py:39:21:39:24 | externally controlled string | +| test.py:38:12:38:42 | externally controlled string | test.py:39:21:39:24 | externally controlled string | +| test.py:38:32:38:40 | externally controlled string | test.py:38:12:38:42 | externally controlled string | +| test.py:38:32:38:40 | externally controlled string | test.py:38:12:38:42 | externally controlled string | +| test.py:53:17:53:28 | dict of externally controlled string | test.py:53:17:53:46 | externally controlled string | +| test.py:53:17:53:28 | dict of externally controlled string | test.py:53:17:53:46 | externally controlled string | +| test.py:53:17:53:46 | externally controlled string | test.py:54:14:54:22 | externally controlled string | +| test.py:53:17:53:46 | externally controlled string | test.py:54:14:54:22 | externally controlled string | +| test.py:54:14:54:22 | externally controlled string | test.py:54:14:54:41 | externally controlled string | +| test.py:54:14:54:22 | externally controlled string | test.py:54:14:54:41 | externally controlled string | +| test.py:54:14:54:41 | externally controlled string | test.py:55:21:55:26 | externally controlled string | +| test.py:54:14:54:41 | externally controlled string | test.py:55:21:55:26 | externally controlled string | +| test.py:60:17:60:28 | dict of externally controlled string | test.py:60:17:60:46 | externally controlled string | +| test.py:60:17:60:28 | dict of externally controlled string | test.py:60:17:60:46 | externally controlled string | +| test.py:60:17:60:46 | externally controlled string | test.py:61:40:61:48 | externally controlled string | +| test.py:60:17:60:46 | externally controlled string | test.py:61:40:61:48 | externally controlled string | +| test.py:61:14:61:49 | externally controlled string | test.py:62:21:62:26 | externally controlled string | +| test.py:61:14:61:49 | externally controlled string | test.py:62:21:62:26 | externally controlled string | +| test.py:61:40:61:48 | externally controlled string | test.py:61:14:61:49 | externally controlled string | +| test.py:61:40:61:48 | externally controlled string | test.py:61:14:61:49 | externally controlled string | +| test.py:67:17:67:28 | dict of externally controlled string | test.py:67:17:67:46 | externally controlled string | +| test.py:67:17:67:28 | dict of externally controlled string | test.py:67:17:67:46 | externally controlled string | +| test.py:67:17:67:46 | externally controlled string | test.py:68:17:68:25 | externally controlled string | +| test.py:67:17:67:46 | externally controlled string | test.py:68:17:68:25 | externally controlled string | +| test.py:68:14:68:41 | externally controlled string | test.py:69:21:69:26 | externally controlled string | +| test.py:68:14:68:41 | externally controlled string | test.py:69:21:69:26 | externally controlled string | +| test.py:68:17:68:25 | externally controlled string | test.py:68:14:68:41 | externally controlled string | +| test.py:68:17:68:25 | externally controlled string | test.py:68:14:68:41 | externally controlled string | #select | test.py:8:21:8:26 | target | test.py:7:14:7:25 | dict of externally controlled string | test.py:8:21:8:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:7:14:7:25 | Attribute | a user-provided value | +| test.py:32:21:32:24 | safe | test.py:30:17:30:28 | dict of externally controlled string | test.py:32:21:32:24 | externally controlled string | Untrusted URL redirection due to $@. | test.py:30:17:30:28 | Attribute | a user-provided value | +| test.py:39:21:39:24 | safe | test.py:37:17:37:28 | dict of externally controlled string | test.py:39:21:39:24 | externally controlled string | Untrusted URL redirection due to $@. | test.py:37:17:37:28 | Attribute | a user-provided value | +| test.py:55:21:55:26 | unsafe | test.py:53:17:53:28 | dict of externally controlled string | test.py:55:21:55:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:53:17:53:28 | Attribute | a user-provided value | +| test.py:62:21:62:26 | unsafe | test.py:60:17:60:28 | dict of externally controlled string | test.py:62:21:62:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:60:17:60:28 | Attribute | a user-provided value | +| test.py:69:21:69:26 | unsafe | test.py:67:17:67:28 | dict of externally controlled string | test.py:69:21:69:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:67:17:67:28 | Attribute | a user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601/options b/python/ql/test/query-tests/Security/CWE-601/options index 84717fe64cf..28b616e5f19 100644 --- a/python/ql/test/query-tests/Security/CWE-601/options +++ b/python/ql/test/query-tests/Security/CWE-601/options @@ -1 +1 @@ -semmle-extractor-options: --max-import-depth=2 -p ../lib +semmle-extractor-options: --lang=3 --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/CWE-601/test.py index 3943f7276bd..dfc9e37281d 100644 --- a/python/ql/test/query-tests/Security/CWE-601/test.py +++ b/python/ql/test/query-tests/Security/CWE-601/test.py @@ -8,11 +8,69 @@ def hello(): return redirect(target, code=302) -#Check for safe prefixes +# Check for safe prefixes @app.route('/ok') def ok(): - untrusted = request.args.get('ok', '') - safe = "safe" + untrusted = request.args.get('target', '') + safe = "https://safe.com/" safe += untrusted return redirect(safe, code=302) + + +@app.route('/ok2') +def ok2(): + untrusted = request.args.get('target', '') + safe = "https://safe.com/" + untrusted + return redirect(safe, code=302) + + +@app.route('/ok3') +def ok3(): + untrusted = request.args.get('target', '') + safe = "https://safe.com/{}".format(untrusted) + return redirect(safe, code=302) # FP + + +@app.route('/ok4') +def ok4(): + untrusted = request.args.get('target', '') + safe = f"https://safe.com/{untrusted}" + return redirect(safe, code=302) # FP + + +@app.route('/ok5') +def ok5(): + untrusted = request.args.get('target', '') + safe = "https://safe.com/%s" % untrusted + return redirect(safe, code=302) + + +# Check that our sanitizer is not too broad + +@app.route('/not_ok1') +def not_ok1(): + untrusted = request.args.get('target', '') + unsafe = untrusted + "?login=success" + return redirect(unsafe, code=302) + + +@app.route('/not_ok2') +def not_ok2(): + untrusted = request.args.get('target', '') + unsafe = "{}?login=success".format(untrusted) + return redirect(unsafe, code=302) + + +@app.route('/not_ok3') +def not_ok3(): + untrusted = request.args.get('target', '') + unsafe = f"{untrusted}?login=success" + return redirect(unsafe, code=302) + + +@app.route('/not_ok4') +def not_ok4(): + untrusted = request.args.get('target', '') + unsafe = "%s?login=success" % untrusted + return redirect(unsafe, code=302) # Missing result From d8bfa3565fb117a1586cd5aa9d443e2558000ef3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 15:44:51 +0100 Subject: [PATCH 019/429] Python: Simple port of URL redirect query Still have not added sanitizer, but seems like old sanitizer was a bit too broad (also covering %-formatting) --- .../2021-01-19-port-url-redirect-query.md | 2 + python/ql/src/Security/CWE-601/UrlRedirect.ql | 32 ++----- .../CWE-601/UrlRedirect.ql | 41 +++++++++ .../python/security/dataflow/UrlRedirect.qll | 28 ++++++ .../Security/CWE-601/UrlRedirect.expected | 91 +++++++++---------- .../test/query-tests/Security/CWE-601/test.py | 8 +- 6 files changed, 122 insertions(+), 80 deletions(-) create mode 100644 python/change-notes/2021-01-19-port-url-redirect-query.md create mode 100644 python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql create mode 100644 python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll diff --git a/python/change-notes/2021-01-19-port-url-redirect-query.md b/python/change-notes/2021-01-19-port-url-redirect-query.md new file mode 100644 index 00000000000..a80093bc0f2 --- /dev/null +++ b/python/change-notes/2021-01-19-port-url-redirect-query.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Ported URL redirection (`py/url-redirection`) query to use new data-flow library. This might result in different results, but overall a more robust and accurate analysis. diff --git a/python/ql/src/Security/CWE-601/UrlRedirect.ql b/python/ql/src/Security/CWE-601/UrlRedirect.ql index cb517043a36..944726e1c98 100644 --- a/python/ql/src/Security/CWE-601/UrlRedirect.ql +++ b/python/ql/src/Security/CWE-601/UrlRedirect.ql @@ -12,30 +12,10 @@ */ import python -import semmle.python.security.Paths -import semmle.python.web.HttpRedirect -import semmle.python.web.HttpRequest -import semmle.python.security.strings.Untrusted +import semmle.python.security.dataflow.UrlRedirect +import DataFlow::PathGraph -/** Url redirection is a problem only if the user controls the prefix of the URL */ -class UntrustedPrefixStringKind extends UntrustedStringKind { - override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { - result = UntrustedStringKind.super.getTaintForFlowStep(fromnode, tonode) and - not tonode.(BinaryExprNode).getRight() = fromnode - } -} - -class UrlRedirectConfiguration extends TaintTracking::Configuration { - UrlRedirectConfiguration() { this = "URL redirect configuration" } - - override predicate isSource(TaintTracking::Source source) { - source instanceof HttpRequestTaintSource - } - - override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpRedirectTaintSink } -} - -from UrlRedirectConfiguration config, TaintedPathSource src, TaintedPathSink sink -where config.hasFlowPath(src, sink) -select sink.getSink(), src, sink, "Untrusted URL redirection due to $@.", src.getSource(), - "a user-provided value" +from UrlRedirectConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Untrusted URL redirection due to $@.", source.getNode(), + "A user-provided value" diff --git a/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql b/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql new file mode 100644 index 00000000000..cb517043a36 --- /dev/null +++ b/python/ql/src/experimental/Security-old-dataflow/CWE-601/UrlRedirect.ql @@ -0,0 +1,41 @@ +/** + * @name URL redirection from remote source + * @description URL redirection based on unvalidated user input + * may cause redirection to malicious web sites. + * @kind path-problem + * @problem.severity error + * @sub-severity low + * @id py/url-redirection + * @tags security + * external/cwe/cwe-601 + * @precision high + */ + +import python +import semmle.python.security.Paths +import semmle.python.web.HttpRedirect +import semmle.python.web.HttpRequest +import semmle.python.security.strings.Untrusted + +/** Url redirection is a problem only if the user controls the prefix of the URL */ +class UntrustedPrefixStringKind extends UntrustedStringKind { + override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { + result = UntrustedStringKind.super.getTaintForFlowStep(fromnode, tonode) and + not tonode.(BinaryExprNode).getRight() = fromnode + } +} + +class UrlRedirectConfiguration extends TaintTracking::Configuration { + UrlRedirectConfiguration() { this = "URL redirect configuration" } + + override predicate isSource(TaintTracking::Source source) { + source instanceof HttpRequestTaintSource + } + + override predicate isSink(TaintTracking::Sink sink) { sink instanceof HttpRedirectTaintSink } +} + +from UrlRedirectConfiguration config, TaintedPathSource src, TaintedPathSink sink +where config.hasFlowPath(src, sink) +select sink.getSink(), src, sink, "Untrusted URL redirection due to $@.", src.getSource(), + "a user-provided value" diff --git a/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll b/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll new file mode 100644 index 00000000000..d43df8417b0 --- /dev/null +++ b/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll @@ -0,0 +1,28 @@ +/** + * Provides a taint-tracking configuration for detecting URL redirection + * vulnerabilities. + */ + +import python +import semmle.python.dataflow.new.DataFlow +import semmle.python.dataflow.new.TaintTracking +import semmle.python.Concepts +import semmle.python.dataflow.new.RemoteFlowSources +import semmle.python.dataflow.new.BarrierGuards + +/** + * A taint-tracking configuration for detecting URL redirection vulnerabilities. + */ +class UrlRedirectConfiguration extends TaintTracking::Configuration { + UrlRedirectConfiguration() { this = "UrlRedirectConfiguration" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { + sink = any(HTTP::Server::HttpRedirectResponse e).getRedirectLocation() + } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof StringConstCompare + } +} diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected index ec681a905a5..e1bcf5948d9 100644 --- a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected @@ -1,52 +1,43 @@ edges -| test.py:7:14:7:25 | dict of externally controlled string | test.py:7:14:7:43 | externally controlled string | -| test.py:7:14:7:25 | dict of externally controlled string | test.py:7:14:7:43 | externally controlled string | -| test.py:7:14:7:43 | externally controlled string | test.py:8:21:8:26 | externally controlled string | -| test.py:7:14:7:43 | externally controlled string | test.py:8:21:8:26 | externally controlled string | -| test.py:30:17:30:28 | dict of externally controlled string | test.py:30:17:30:46 | externally controlled string | -| test.py:30:17:30:28 | dict of externally controlled string | test.py:30:17:30:46 | externally controlled string | -| test.py:30:17:30:46 | externally controlled string | test.py:31:41:31:49 | externally controlled string | -| test.py:30:17:30:46 | externally controlled string | test.py:31:41:31:49 | externally controlled string | -| test.py:31:12:31:50 | externally controlled string | test.py:32:21:32:24 | externally controlled string | -| test.py:31:12:31:50 | externally controlled string | test.py:32:21:32:24 | externally controlled string | -| test.py:31:41:31:49 | externally controlled string | test.py:31:12:31:50 | externally controlled string | -| test.py:31:41:31:49 | externally controlled string | test.py:31:12:31:50 | externally controlled string | -| test.py:37:17:37:28 | dict of externally controlled string | test.py:37:17:37:46 | externally controlled string | -| test.py:37:17:37:28 | dict of externally controlled string | test.py:37:17:37:46 | externally controlled string | -| test.py:37:17:37:46 | externally controlled string | test.py:38:32:38:40 | externally controlled string | -| test.py:37:17:37:46 | externally controlled string | test.py:38:32:38:40 | externally controlled string | -| test.py:38:12:38:42 | externally controlled string | test.py:39:21:39:24 | externally controlled string | -| test.py:38:12:38:42 | externally controlled string | test.py:39:21:39:24 | externally controlled string | -| test.py:38:32:38:40 | externally controlled string | test.py:38:12:38:42 | externally controlled string | -| test.py:38:32:38:40 | externally controlled string | test.py:38:12:38:42 | externally controlled string | -| test.py:53:17:53:28 | dict of externally controlled string | test.py:53:17:53:46 | externally controlled string | -| test.py:53:17:53:28 | dict of externally controlled string | test.py:53:17:53:46 | externally controlled string | -| test.py:53:17:53:46 | externally controlled string | test.py:54:14:54:22 | externally controlled string | -| test.py:53:17:53:46 | externally controlled string | test.py:54:14:54:22 | externally controlled string | -| test.py:54:14:54:22 | externally controlled string | test.py:54:14:54:41 | externally controlled string | -| test.py:54:14:54:22 | externally controlled string | test.py:54:14:54:41 | externally controlled string | -| test.py:54:14:54:41 | externally controlled string | test.py:55:21:55:26 | externally controlled string | -| test.py:54:14:54:41 | externally controlled string | test.py:55:21:55:26 | externally controlled string | -| test.py:60:17:60:28 | dict of externally controlled string | test.py:60:17:60:46 | externally controlled string | -| test.py:60:17:60:28 | dict of externally controlled string | test.py:60:17:60:46 | externally controlled string | -| test.py:60:17:60:46 | externally controlled string | test.py:61:40:61:48 | externally controlled string | -| test.py:60:17:60:46 | externally controlled string | test.py:61:40:61:48 | externally controlled string | -| test.py:61:14:61:49 | externally controlled string | test.py:62:21:62:26 | externally controlled string | -| test.py:61:14:61:49 | externally controlled string | test.py:62:21:62:26 | externally controlled string | -| test.py:61:40:61:48 | externally controlled string | test.py:61:14:61:49 | externally controlled string | -| test.py:61:40:61:48 | externally controlled string | test.py:61:14:61:49 | externally controlled string | -| test.py:67:17:67:28 | dict of externally controlled string | test.py:67:17:67:46 | externally controlled string | -| test.py:67:17:67:28 | dict of externally controlled string | test.py:67:17:67:46 | externally controlled string | -| test.py:67:17:67:46 | externally controlled string | test.py:68:17:68:25 | externally controlled string | -| test.py:67:17:67:46 | externally controlled string | test.py:68:17:68:25 | externally controlled string | -| test.py:68:14:68:41 | externally controlled string | test.py:69:21:69:26 | externally controlled string | -| test.py:68:14:68:41 | externally controlled string | test.py:69:21:69:26 | externally controlled string | -| test.py:68:17:68:25 | externally controlled string | test.py:68:14:68:41 | externally controlled string | -| test.py:68:17:68:25 | externally controlled string | test.py:68:14:68:41 | externally controlled string | +| test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target | +| test.py:15:17:15:28 | ControlFlowNode for Attribute | test.py:18:21:18:24 | ControlFlowNode for safe | +| test.py:23:17:23:28 | ControlFlowNode for Attribute | test.py:25:21:25:24 | ControlFlowNode for safe | +| test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | +| test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | +| test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | +| test.py:53:17:53:28 | ControlFlowNode for Attribute | test.py:55:21:55:26 | ControlFlowNode for unsafe | +| test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:62:21:62:26 | ControlFlowNode for unsafe | +| test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:69:21:69:26 | ControlFlowNode for unsafe | +| test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:76:21:76:26 | ControlFlowNode for unsafe | +nodes +| test.py:7:14:7:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:8:21:8:26 | ControlFlowNode for target | semmle.label | ControlFlowNode for target | +| test.py:15:17:15:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:18:21:18:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | +| test.py:23:17:23:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:25:21:25:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | +| test.py:30:17:30:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:32:21:32:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | +| test.py:37:17:37:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:39:21:39:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | +| test.py:44:17:44:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:46:21:46:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | +| test.py:53:17:53:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:55:21:55:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | +| test.py:60:17:60:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:62:21:62:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | +| test.py:67:17:67:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:69:21:69:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | +| test.py:74:17:74:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:76:21:76:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | #select -| test.py:8:21:8:26 | target | test.py:7:14:7:25 | dict of externally controlled string | test.py:8:21:8:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:7:14:7:25 | Attribute | a user-provided value | -| test.py:32:21:32:24 | safe | test.py:30:17:30:28 | dict of externally controlled string | test.py:32:21:32:24 | externally controlled string | Untrusted URL redirection due to $@. | test.py:30:17:30:28 | Attribute | a user-provided value | -| test.py:39:21:39:24 | safe | test.py:37:17:37:28 | dict of externally controlled string | test.py:39:21:39:24 | externally controlled string | Untrusted URL redirection due to $@. | test.py:37:17:37:28 | Attribute | a user-provided value | -| test.py:55:21:55:26 | unsafe | test.py:53:17:53:28 | dict of externally controlled string | test.py:55:21:55:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:53:17:53:28 | Attribute | a user-provided value | -| test.py:62:21:62:26 | unsafe | test.py:60:17:60:28 | dict of externally controlled string | test.py:62:21:62:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:60:17:60:28 | Attribute | a user-provided value | -| test.py:69:21:69:26 | unsafe | test.py:67:17:67:28 | dict of externally controlled string | test.py:69:21:69:26 | externally controlled string | Untrusted URL redirection due to $@. | test.py:67:17:67:28 | Attribute | a user-provided value | +| test.py:8:21:8:26 | ControlFlowNode for target | test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection due to $@. | test.py:7:14:7:25 | ControlFlowNode for Attribute | A user-provided value | +| test.py:18:21:18:24 | ControlFlowNode for safe | test.py:15:17:15:28 | ControlFlowNode for Attribute | test.py:18:21:18:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:15:17:15:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:25:21:25:24 | ControlFlowNode for safe | test.py:23:17:23:28 | ControlFlowNode for Attribute | test.py:25:21:25:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:23:17:23:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:32:21:32:24 | ControlFlowNode for safe | test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:30:17:30:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:39:21:39:24 | ControlFlowNode for safe | test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:37:17:37:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:46:21:46:24 | ControlFlowNode for safe | test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:44:17:44:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:55:21:55:26 | ControlFlowNode for unsafe | test.py:53:17:53:28 | ControlFlowNode for Attribute | test.py:55:21:55:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:53:17:53:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:60:17:60:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:67:17:67:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:74:17:74:28 | ControlFlowNode for Attribute | A user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/CWE-601/test.py index dfc9e37281d..680038576e1 100644 --- a/python/ql/test/query-tests/Security/CWE-601/test.py +++ b/python/ql/test/query-tests/Security/CWE-601/test.py @@ -15,14 +15,14 @@ def ok(): untrusted = request.args.get('target', '') safe = "https://safe.com/" safe += untrusted - return redirect(safe, code=302) + return redirect(safe, code=302) # FP @app.route('/ok2') def ok2(): untrusted = request.args.get('target', '') safe = "https://safe.com/" + untrusted - return redirect(safe, code=302) + return redirect(safe, code=302) # FP @app.route('/ok3') @@ -43,7 +43,7 @@ def ok4(): def ok5(): untrusted = request.args.get('target', '') safe = "https://safe.com/%s" % untrusted - return redirect(safe, code=302) + return redirect(safe, code=302) # FP # Check that our sanitizer is not too broad @@ -73,4 +73,4 @@ def not_ok3(): def not_ok4(): untrusted = request.args.get('target', '') unsafe = "%s?login=success" % untrusted - return redirect(unsafe, code=302) # Missing result + return redirect(unsafe, code=302) From 37aa9b9d060dceb2a6b8f080f0fa78655454b6d5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 16:08:10 +0100 Subject: [PATCH 020/429] Python: Add prefix sanitizer on URL redirect query This doesn't cover 100% of what we want to, but matches what we used to. --- .../src/semmle/python/security/dataflow/UrlRedirect.qll | 9 +++++++++ .../query-tests/Security/CWE-601/UrlRedirect.expected | 8 -------- python/ql/test/query-tests/Security/CWE-601/test.py | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll b/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll index d43df8417b0..7017bf8aa29 100644 --- a/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll +++ b/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll @@ -22,6 +22,15 @@ class UrlRedirectConfiguration extends TaintTracking::Configuration { sink = any(HTTP::Server::HttpRedirectResponse e).getRedirectLocation() } + override predicate isSanitizer(DataFlow::Node node) { + // Url redirection is a problem only if the user controls the prefix of the URL. + // This is a copy of the taint-sanitizer from the old points-to query, which doesn't + // cover formatting. + exists(BinaryExprNode string_concat | string_concat.getOp() instanceof Add | + string_concat.getRight() = node.asCfgNode() + ) + } + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof StringConstCompare } diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected index e1bcf5948d9..1e108f545ca 100644 --- a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected @@ -1,7 +1,5 @@ edges | test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target | -| test.py:15:17:15:28 | ControlFlowNode for Attribute | test.py:18:21:18:24 | ControlFlowNode for safe | -| test.py:23:17:23:28 | ControlFlowNode for Attribute | test.py:25:21:25:24 | ControlFlowNode for safe | | test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | | test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | | test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | @@ -12,10 +10,6 @@ edges nodes | test.py:7:14:7:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:8:21:8:26 | ControlFlowNode for target | semmle.label | ControlFlowNode for target | -| test.py:15:17:15:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:18:21:18:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:23:17:23:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:25:21:25:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | | test.py:30:17:30:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:32:21:32:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | | test.py:37:17:37:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | @@ -32,8 +26,6 @@ nodes | test.py:76:21:76:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | #select | test.py:8:21:8:26 | ControlFlowNode for target | test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection due to $@. | test.py:7:14:7:25 | ControlFlowNode for Attribute | A user-provided value | -| test.py:18:21:18:24 | ControlFlowNode for safe | test.py:15:17:15:28 | ControlFlowNode for Attribute | test.py:18:21:18:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:15:17:15:28 | ControlFlowNode for Attribute | A user-provided value | -| test.py:25:21:25:24 | ControlFlowNode for safe | test.py:23:17:23:28 | ControlFlowNode for Attribute | test.py:25:21:25:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:23:17:23:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:32:21:32:24 | ControlFlowNode for safe | test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:30:17:30:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:39:21:39:24 | ControlFlowNode for safe | test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:37:17:37:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:46:21:46:24 | ControlFlowNode for safe | test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:44:17:44:28 | ControlFlowNode for Attribute | A user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/CWE-601/test.py index 680038576e1..a2aee6562b2 100644 --- a/python/ql/test/query-tests/Security/CWE-601/test.py +++ b/python/ql/test/query-tests/Security/CWE-601/test.py @@ -15,14 +15,14 @@ def ok(): untrusted = request.args.get('target', '') safe = "https://safe.com/" safe += untrusted - return redirect(safe, code=302) # FP + return redirect(safe, code=302) @app.route('/ok2') def ok2(): untrusted = request.args.get('target', '') safe = "https://safe.com/" + untrusted - return redirect(safe, code=302) # FP + return redirect(safe, code=302) @app.route('/ok3') From 526ccdd2279c20c4de657be44f2c2cba31462633 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 19 Jan 2021 16:21:27 +0100 Subject: [PATCH 021/429] Python: Add safe example from qhelp to qltests --- .../query-tests/Security/CWE-601/UrlRedirect.expected | 8 ++++---- python/ql/test/query-tests/Security/CWE-601/test.py | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected index 1e108f545ca..53098240671 100644 --- a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected @@ -3,10 +3,10 @@ edges | test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | | test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | | test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | -| test.py:53:17:53:28 | ControlFlowNode for Attribute | test.py:55:21:55:26 | ControlFlowNode for unsafe | | test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:62:21:62:26 | ControlFlowNode for unsafe | | test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:69:21:69:26 | ControlFlowNode for unsafe | | test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:76:21:76:26 | ControlFlowNode for unsafe | +| test.py:81:17:81:28 | ControlFlowNode for Attribute | test.py:83:21:83:26 | ControlFlowNode for unsafe | nodes | test.py:7:14:7:25 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:8:21:8:26 | ControlFlowNode for target | semmle.label | ControlFlowNode for target | @@ -16,20 +16,20 @@ nodes | test.py:39:21:39:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | | test.py:44:17:44:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:46:21:46:24 | ControlFlowNode for safe | semmle.label | ControlFlowNode for safe | -| test.py:53:17:53:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | -| test.py:55:21:55:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | | test.py:60:17:60:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:62:21:62:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | | test.py:67:17:67:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:69:21:69:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | | test.py:74:17:74:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | | test.py:76:21:76:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | +| test.py:81:17:81:28 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute | +| test.py:83:21:83:26 | ControlFlowNode for unsafe | semmle.label | ControlFlowNode for unsafe | #select | test.py:8:21:8:26 | ControlFlowNode for target | test.py:7:14:7:25 | ControlFlowNode for Attribute | test.py:8:21:8:26 | ControlFlowNode for target | Untrusted URL redirection due to $@. | test.py:7:14:7:25 | ControlFlowNode for Attribute | A user-provided value | | test.py:32:21:32:24 | ControlFlowNode for safe | test.py:30:17:30:28 | ControlFlowNode for Attribute | test.py:32:21:32:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:30:17:30:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:39:21:39:24 | ControlFlowNode for safe | test.py:37:17:37:28 | ControlFlowNode for Attribute | test.py:39:21:39:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:37:17:37:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:46:21:46:24 | ControlFlowNode for safe | test.py:44:17:44:28 | ControlFlowNode for Attribute | test.py:46:21:46:24 | ControlFlowNode for safe | Untrusted URL redirection due to $@. | test.py:44:17:44:28 | ControlFlowNode for Attribute | A user-provided value | -| test.py:55:21:55:26 | ControlFlowNode for unsafe | test.py:53:17:53:28 | ControlFlowNode for Attribute | test.py:55:21:55:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:53:17:53:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:62:21:62:26 | ControlFlowNode for unsafe | test.py:60:17:60:28 | ControlFlowNode for Attribute | test.py:62:21:62:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:60:17:60:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:69:21:69:26 | ControlFlowNode for unsafe | test.py:67:17:67:28 | ControlFlowNode for Attribute | test.py:69:21:69:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:67:17:67:28 | ControlFlowNode for Attribute | A user-provided value | | test.py:76:21:76:26 | ControlFlowNode for unsafe | test.py:74:17:74:28 | ControlFlowNode for Attribute | test.py:76:21:76:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:74:17:74:28 | ControlFlowNode for Attribute | A user-provided value | +| test.py:83:21:83:26 | ControlFlowNode for unsafe | test.py:81:17:81:28 | ControlFlowNode for Attribute | test.py:83:21:83:26 | ControlFlowNode for unsafe | Untrusted URL redirection due to $@. | test.py:81:17:81:28 | ControlFlowNode for Attribute | A user-provided value | diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/CWE-601/test.py index a2aee6562b2..381eb3a4bae 100644 --- a/python/ql/test/query-tests/Security/CWE-601/test.py +++ b/python/ql/test/query-tests/Security/CWE-601/test.py @@ -46,6 +46,13 @@ def ok5(): return redirect(safe, code=302) # FP +@app.route('/const-str-compare') +def const_str_compare(): + target = request.args.get('target', '') + if target == "example.com/": + return redirect(target, code=302) + + # Check that our sanitizer is not too broad @app.route('/not_ok1') From 5c6f5b7b33311d5a0072361c0828af0d3077a1a2 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 20 Jan 2021 16:53:03 +0000 Subject: [PATCH 022/429] Java: Track taint through Spring Java bean getters on super types --- .../code/java/dataflow/internal/TaintTrackingUtil.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index b627d59783f..35f820f9521 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -345,7 +345,9 @@ private predicate taintPreservingQualifierToMethod(Method m) { m.getDeclaringType() instanceof TypeUri and m.hasName("toURL") or - m instanceof GetterMethod and m.getDeclaringType() instanceof SpringUntrustedDataType + m instanceof GetterMethod and + m.getDeclaringType().getASubtype*() instanceof SpringUntrustedDataType and + not m.getDeclaringType() instanceof TypeObject or m.getDeclaringType() instanceof SpringHttpEntity and m.getName().regexpMatch("getBody|getHeaders") @@ -684,7 +686,8 @@ private class FormatterCallable extends TaintPreservingCallable { ( this.hasName(["format", "out", "toString"]) or - this.(Constructor) + this + .(Constructor) .getParameterType(0) .(RefType) .getASourceSupertype*() From 48083d657a3d5552c334ec7aa126456dce30da3a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 21 Jan 2021 13:40:58 +0100 Subject: [PATCH 023/429] Python: Apply code-review suggestion Co-authored-by: yoff --- python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll b/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll index 7017bf8aa29..27c1dabab98 100644 --- a/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll +++ b/python/ql/src/semmle/python/security/dataflow/UrlRedirect.qll @@ -24,7 +24,7 @@ class UrlRedirectConfiguration extends TaintTracking::Configuration { override predicate isSanitizer(DataFlow::Node node) { // Url redirection is a problem only if the user controls the prefix of the URL. - // This is a copy of the taint-sanitizer from the old points-to query, which doesn't + // TODO: This is a copy of the taint-sanitizer from the old points-to query, which doesn't // cover formatting. exists(BinaryExprNode string_concat | string_concat.getOp() instanceof Add | string_concat.getRight() = node.asCfgNode() From 2f86937e5ae5f58693f55a32856b9cdfe475321a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 21 Jan 2021 13:44:56 +0100 Subject: [PATCH 024/429] Python: Remove unused param in test code --- .../library-tests/frameworks/django-v1/response_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py index 69cdd899c8d..f214cfb63d3 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py @@ -21,7 +21,7 @@ def or__redirect(request): next = request.GET.get("next") return HttpResponseRedirect(next) # $HttpResponse mimetype=text/html HttpRedirectResponse redirectLocation=next -def information_exposure_through_redirect(request, as_kw=False, perm_redirect=False): +def information_exposure_through_redirect(request, as_kw=False): # This is a contrived example, but possible private = "private" next = request.GET.get("next") From 7a76a5134e7e01537231fc6f7a23dd51965ad913 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 21 Jan 2021 14:04:11 +0100 Subject: [PATCH 025/429] Python: Add redirect modeling for Tornado After making https://github.com/github/codeql/pull/4995, I realized how easy this would be :D Will need to do some manual merge-conflict handling, but it should be all good :) --- .../src/semmle/python/frameworks/Tornado.qll | 38 +++++++++++++++++++ .../library-tests/frameworks/tornado/basic.py | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Tornado.qll b/python/ql/src/semmle/python/frameworks/Tornado.qll index 995fb19747d..29c91654b4a 100644 --- a/python/ql/src/semmle/python/frameworks/Tornado.qll +++ b/python/ql/src/semmle/python/frameworks/Tornado.qll @@ -216,6 +216,17 @@ private module Tornado { /** Gets a reference to one of the methods `get_arguments`, `get_body_arguments`, `get_query_arguments`. */ DataFlow::Node argumentsMethod() { result = argumentsMethod(DataFlow::TypeTracker::end()) } + /** Gets a reference the `redirect` method. */ + private DataFlow::Node redirectMethod(DataFlow::TypeTracker t) { + t.startInAttr("redirect") and + result = instance() + or + exists(DataFlow::TypeTracker t2 | result = redirectMethod(t2).track(t2, t)) + } + + /** Gets a reference the `redirect` method. */ + DataFlow::Node redirectMethod() { result = redirectMethod(DataFlow::TypeTracker::end()) } + private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep { override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { // Method access @@ -540,4 +551,31 @@ private module Tornado { not result = this.getArg(0) } } + + // --------------------------------------------------------------------------- + // Response modeling + // --------------------------------------------------------------------------- + /** + * A call to `tornado.web.RequestHandler.write` method. + * + * See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.write + */ + private class TornadoRequestHandlerRedirectCall extends HTTP::Server::HttpRedirectResponse::Range, + DataFlow::CfgNode { + override CallNode node; + + TornadoRequestHandlerRedirectCall() { + node.getFunction() = tornado::web::RequestHandler::redirectMethod().asCfgNode() + } + + override DataFlow::Node getRedirectLocation() { + result.asCfgNode() in [node.getArg(0), node.getArgByName("url")] + } + + override DataFlow::Node getBody() { none() } + + override string getMimetypeDefault() { none() } + + override DataFlow::Node getMimetypeOrContentTypeArg() { none() } + } } diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/basic.py b/python/ql/test/experimental/library-tests/frameworks/tornado/basic.py index 6733de040b1..24b37d74a1b 100644 --- a/python/ql/test/experimental/library-tests/frameworks/tornado/basic.py +++ b/python/ql/test/experimental/library-tests/frameworks/tornado/basic.py @@ -25,7 +25,7 @@ class RedirectHandler(tornado.web.RequestHandler): req = self.request h = req.headers url = h["url"] - self.redirect(url) + self.redirect(url) # $ HttpRedirectResponse HttpResponse redirectLocation=url class BaseReverseInheritance(tornado.web.RequestHandler): From 9071ba2f99ef3f09732999b517a72d45b30c210e Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Mon, 25 Jan 2021 00:06:19 +0300 Subject: [PATCH 026/429] Add files via upload --- ...ctingAndHandlingMemoryAllocationErrors.cpp | 32 +++++++ ...ingAndHandlingMemoryAllocationErrors.qhelp | 29 ++++++ ...ectingAndHandlingMemoryAllocationErrors.ql | 93 +++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp new file mode 100644 index 00000000000..6fc3bc2f893 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp @@ -0,0 +1,32 @@ +// BAD: no memory allocation errors are detected +void f(const int *array, std::size_t size) noexcept { + int *copy = new int[size]; + std::memcpy(copy, array, size * sizeof(*copy)); + // ... + delete [] copy; +} +// GOOD: memory allocation errors are detected +void f(const int *array, std::size_t size) noexcept { + int *copy; + try { + copy = new int[size]; + } catch(std::bad_alloc) { + // Handle error + return; + } + // At this point, copy has been initialized to allocated memory + std::memcpy(copy, array, size * sizeof(*copy)); + // ... + delete [] copy; +} +// GOOD: memory allocation errors are detected +void f(const int *array, std::size_t size) noexcept { + int *copy = new (std::nothrow) int[size]; + if (!copy) { + // Handle error + return; + } + std::memcpy(copy, array, size * sizeof(*copy)); + // ... + delete [] copy; +} diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp new file mode 100644 index 00000000000..4b7941a5846 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp @@ -0,0 +1,29 @@ + + + +

    when using the new operator to allocate memory, you need to pay attention to the different way of detecting errors. so ::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. the programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    + +

    Loss of detection probably refers to use cases where memory allocation using your own solutions with strong nesting. It is also possible when using a buffer in the form of fields of different structures with the same names.

    + +
    + + +

    We recommend using the error detection method, depending on the selected memory allocation method..

    + + + +

    The following file demonstrates various approaches to detecting memory allocation errors using the new operator.

    + + +
    + + +
  • + CERT C++ Coding Standard: +MEM52-CPP. Detect and handle memory allocation errors. +
  • + +
    + diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql new file mode 100644 index 00000000000..383c8a1f128 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -0,0 +1,93 @@ +/** + * @name Сonfusion In Detecting And Handling Memory Allocation Errors + * @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. + * --the programmer can get confused when check the error that occurs when allocating memory incorrectly. + * --Making a call of this type may result in a zero byte being written just outside the buffer. + * @kind problem + * @id cpp/detect-and-handle-memory-allocation-errors + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-570 + */ + +import cpp + +/** + * Lookup if condition compare with 0 + */ +class IfCompareWithZero extends IfStmt { + IfCompareWithZero() { + this.getCondition().(EQExpr).getAChild().getValue() = "0" + or + this.getCondition().(NEExpr).getAChild().getValue() = "0" and + this.hasElse() + } +} + +/** + * lookup for calls to `operator new`, with incorrect error handling. + */ +class WrongCheckErrorOperatorNew extends FunctionCall { + Expr exp; + + WrongCheckErrorOperatorNew() { + this = exp.(NewOrNewArrayExpr).getAChild().(FunctionCall) and + ( + this.getTarget().hasGlobalOrStdName("operator new") + or + this.getTarget().hasGlobalOrStdName("operator new[]") + ) + } + + /** + * Holds if handler `try ... catch` exists. + */ + predicate isExistsTryCatchBlock() { + exists(TryStmt tb, AssignExpr aex, Initializer it | + tb.getAChild*() = exp + or + exp = it.getExpr() and + tb.getAChild*().(DeclStmt).getADeclaration() = it.getDeclaration() + or + aex.getAChild*() = exp and + tb.getAChild*().(AssignExpr) = aex + ) + } + + /** + * Holds if results call `operator new` check in `operator if`. + */ + predicate isExistsIfCondition() { + exists(IfCompareWithZero ifc, AssignExpr aex, Initializer it | + // call `operator new` directly from the condition of `operator if`. + this = ifc.getCondition().getAChild() + or + // check results call `operator new` with variable appropriation + postDominates(ifc, this) and + aex.getAChild() = exp and + ifc.getCondition().getAChild().(VariableAccess).getTarget() = + aex.getLValue().(VariableAccess).getTarget() + or + // check results call `operator new` with declaration variable + postDominates(ifc, this) and + exp = it.getExpr() and + it.getDeclaration() = ifc.getCondition().getAChild().(VariableAccess).getTarget() + ) + } + + /** + * Holds if `(std::nothrow)` exists in call `operator new`. + */ + predicate isExistsNothrow() { this.getAChild().toString() = "nothrow" } +} + +from WrongCheckErrorOperatorNew op +where + // use call `operator new` with `(std::nothrow)` and checking error using `try ... catch` block and not `operator if` + op.isExistsNothrow() and not op.isExistsIfCondition() and op.isExistsTryCatchBlock() + or + // use call `operator new` without `(std::nothrow)` and checking error using `operator if` and not `try ... catch` block + not op.isExistsNothrow() and not op.isExistsTryCatchBlock() and op.isExistsIfCondition() +select op, "memory allocation error check is incorrect or missing" From 20e19ec4677c1e414fceb17d16de31327967fe5a Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Mon, 25 Jan 2021 00:09:55 +0300 Subject: [PATCH 027/429] Add files via upload --- ...AndHandlingMemoryAllocationErrors.expected | 5 + ...ingAndHandlingMemoryAllocationErrors.qlref | 1 + .../CWE/CWE-570/semmle/tests/test.cpp | 97 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected new file mode 100644 index 00000000000..80e82cff212 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.expected @@ -0,0 +1,5 @@ +| test.cpp:30:15:30:26 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:38:9:38:20 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:50:13:50:38 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:51:22:51:47 | call to operator new[] | memory allocation error check is incorrect or missing | +| test.cpp:53:18:53:43 | call to operator new[] | memory allocation error check is incorrect or missing | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref new file mode 100644 index 00000000000..fc3252ef122 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/WrongInDetectingAndHandlingMemoryAllocationErrors.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp new file mode 100644 index 00000000000..6f03f896024 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp @@ -0,0 +1,97 @@ +#define NULL ((void*)0) +class exception {}; + +namespace std{ + struct nothrow_t {}; + typedef unsigned long size_t; + class bad_alloc{ + const char* what() const throw(); + }; + extern const std::nothrow_t nothrow; +} + +using namespace std; + +void* operator new(std::size_t _Size); +void* operator new[](std::size_t _Size); +void* operator new( std::size_t count, const std::nothrow_t& tag ); +void* operator new[]( std::size_t count, const std::nothrow_t& tag ); + +void badNew_0_0() +{ + while (true) { + new int[100]; + if(!(new int[100])) + return; + } +} +void badNew_0_1() +{ + int * i = new int[100]; + if(i == 0) + return; + if(!i) + return; + if(i == NULL) + return; + int * j; + j = new int[100]; + if(j == 0) + return; + if(!j) + return; + if(j == NULL) + return; +} +void badNew_1_0() +{ + try { + while (true) { + new(std::nothrow) int[100]; + int* p = new(std::nothrow) int[100]; + int* p1; + p1 = new(std::nothrow) int[100]; + } + } catch (const exception &){//const std::bad_alloc& e) { +// std::cout << e.what() << '\n'; + } +} +void badNew_1_1() +{ + while (true) { + int* p = new(std::nothrow) int[100]; + new(std::nothrow) int[100]; + } +} + +void goodNew_0_0() +{ + try { + while (true) { + new int[100]; + } + } catch (const exception &){//const std::bad_alloc& e) { +// std::cout << e.what() << '\n'; + } +} + +void goodNew_1_0() +{ + while (true) { + int* p = new(std::nothrow) int[100]; + if (p == nullptr) { +// std::cout << "Allocation returned nullptr\n"; + break; + } + int* p1; + p1 = new(std::nothrow) int[100]; + if (p1 == nullptr) { +// std::cout << "Allocation returned nullptr\n"; + break; + } + if (new(std::nothrow) int[100] == nullptr) { +// std::cout << "Allocation returned nullptr\n"; + break; + } + } +} From 9ae503a5a820ad535a949e1d13b9f368aea7a1eb Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Mon, 25 Jan 2021 00:30:35 +0300 Subject: [PATCH 028/429] Add files via upload --- ...emoryLocationAfterEndOfBufferUsingStrlen.c | 9 ++++++ ...yLocationAfterEndOfBufferUsingStrlen.qhelp | 31 +++++++++++++++++++ ...moryLocationAfterEndOfBufferUsingStrlen.ql | 25 +++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp create mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c new file mode 100644 index 00000000000..ba78d4b97d1 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.c @@ -0,0 +1,9 @@ +// BAD: if buffer does not have a terminal zero, then access outside the allocated memory is possible. + +buffer[strlen(buffer)] = 0; + + +// GOOD: we will eliminate dangerous behavior if we use a different method of calculating the length. +size_t len; +... +buffer[len] = 0 diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp new file mode 100644 index 00000000000..372a3e1d1c4 --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp @@ -0,0 +1,31 @@ + + + +

    Potentially dangerous use of the strlen function to calculate the length of a string. +The expression buffer[strlen(buffer)] = 0 is potentially dangerous, if the variable buffer does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior. +If terminal zero is present, then the specified expression is meaningless.

    + +

    False positives include heavily nested strlen. This situation is unlikely.

    + +
    + + +

    We recommend using another method for calculating the string length

    + +
    + +

    The following example demonstrates an erroneous and corrected use of the strlen function.

    + + +
    + + +
  • + CERT C Coding Standard: + STR32-C. Do not pass a non-null-terminated character sequence to a library function that expects a string. +
  • + +
    +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql new file mode 100644 index 00000000000..80c7f2104ab --- /dev/null +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql @@ -0,0 +1,25 @@ +/** + * @name Access Of Memory Location After End Of Buffer + * @description --The expression buffer [strlen (buffer)] = 0 is potentially dangerous, if the variable buffer does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior. + * --If terminal zero is present, then the specified expression is meaningless. + * --We recommend using another method for calculating the string length. + * @kind problem + * @id cpp/access-memory-location-after-end-buffer + * @problem.severity warning + * @precision medium + * @tags correctness + * security + * external/cwe/cwe-788 + */ + +import cpp +import semmle.code.cpp.valuenumbering.HashCons + +from FunctionCall fc, AssignExpr expr, ArrayExpr exprarr +where + fc.getTarget().hasGlobalOrStdName("strlen") and + exprarr = expr.getLValue() and + expr.getRValue().getValue().toInt() = 0 and + exprarr.getArrayOffset() = fc and + hashCons(fc.getArgument(0)) = hashCons(exprarr.getArrayBase()) +select expr, "use a different method to calculate the length." From b899229298218b20c34540219088f0bb06170728 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Mon, 25 Jan 2021 00:33:54 +0300 Subject: [PATCH 029/429] Add files via upload --- ...cationAfterEndOfBufferUsingStrlen.expected | 9 ++++ ...yLocationAfterEndOfBufferUsingStrlen.qlref | 1 + .../Security/CWE/CWE-788/semmle/tests/test.c | 44 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected new file mode 100644 index 00000000000..82d3e224993 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected @@ -0,0 +1,9 @@ +| test.c:13:3:13:24 | ... = ... | use a different method to calculate the length. | +| test.c:14:3:14:40 | ... = ... | use a different method to calculate the length. | +| test.c:15:3:15:40 | ... = ... | use a different method to calculate the length. | +| test.c:16:3:16:44 | ... = ... | use a different method to calculate the length. | +| test.c:17:3:17:44 | ... = ... | use a different method to calculate the length. | +| test.c:18:3:18:48 | ... = ... | use a different method to calculate the length. | +| test.c:19:3:19:48 | ... = ... | use a different method to calculate the length. | +| test.c:20:3:20:50 | ... = ... | use a different method to calculate the length. | +| test.c:21:3:21:50 | ... = ... | use a different method to calculate the length. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref new file mode 100644 index 00000000000..6ba005d087a --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c new file mode 100644 index 00000000000..84487670bf7 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c @@ -0,0 +1,44 @@ +struct buffers +{ + unsigned char buff1[50]; + unsigned char *buff2; +} globalBuff1,*globalBuff2,globalBuff1_c,*globalBuff2_c; + + +void badFunc0(){ + unsigned char buff1[12]; + struct buffers buffAll; + struct buffers * buffAll1; + + buff1[strlen(buff1)]=0; + buffAll.buff1[strlen(buffAll.buff1)]=0; + buffAll.buff2[strlen(buffAll.buff2)]=0; + buffAll1->buff1[strlen(buffAll1->buff1)]=0; + buffAll1->buff2[strlen(buffAll1->buff2)]=0; + globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; + globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; + globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; + globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; +} +void noBadFunc0(){ + unsigned char buff1[12],buff1_c[12]; + struct buffers buffAll,buffAll_c; + struct buffers * buffAll1,*buffAll1_c; + + buff1[strlen(buff1_c)]=0; + buffAll.buff1[strlen(buffAll_c.buff1)]=0; + buffAll.buff2[strlen(buffAll.buff1)]=0; + buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; + buffAll1->buff2[strlen(buffAll1->buff1)]=0; + globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; + globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; + globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; + globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; +} +void goodFunc0(){ + unsigned char buffer[12]; + int i; + for(i = 0; i < 6; i++) + buffer[i] = 'A'; + buffer[i]=0; +} From de0bbc8826982276d00bf9edc655443801e3ca5c Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:47:07 +0300 Subject: [PATCH 030/429] Apply suggestions from code review Co-authored-by: Mathias Vorreiter Pedersen --- .../AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp | 2 +- .../AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp index 372a3e1d1c4..51424ce7619 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qhelp @@ -17,7 +17,7 @@ If terminal zero is present, then the specified expression is meaningless.

    The following example demonstrates an erroneous and corrected use of the strlen function.

    - +
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql index 80c7f2104ab..a1d4a169b20 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql @@ -1,8 +1,7 @@ /** * @name Access Of Memory Location After End Of Buffer - * @description --The expression buffer [strlen (buffer)] = 0 is potentially dangerous, if the variable buffer does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior. - * --If terminal zero is present, then the specified expression is meaningless. - * --We recommend using another method for calculating the string length. + * @description The expression `buffer [strlen (buffer)] = 0` is potentially dangerous, if the variable `buffer` does not have a terminal zero, then access beyond the bounds of the allocated memory is possible, which will lead to undefined behavior. + * If terminal zero is present, then the specified expression is meaningless. * @kind problem * @id cpp/access-memory-location-after-end-buffer * @problem.severity warning From fc9d2190574dcf0ab87dcb876a17530493fc35fc Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:50:54 +0300 Subject: [PATCH 031/429] Update AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql --- .../AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql index a1d4a169b20..77fc29719f6 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql @@ -12,13 +12,12 @@ */ import cpp -import semmle.code.cpp.valuenumbering.HashCons +import semmle.code.cpp.valuenumbering.GlobalValueNumbering from FunctionCall fc, AssignExpr expr, ArrayExpr exprarr where - fc.getTarget().hasGlobalOrStdName("strlen") and exprarr = expr.getLValue() and expr.getRValue().getValue().toInt() = 0 and exprarr.getArrayOffset() = fc and - hashCons(fc.getArgument(0)) = hashCons(exprarr.getArrayBase()) -select expr, "use a different method to calculate the length." + globalValueNumber(fc.getArgument(0)) = globalValueNumber(exprarr.getArrayBase()) +select expr, "potential unsafe or redundant assignment." From 636fe73f400782951db790ee8bd4f826f0686fd1 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:52:18 +0300 Subject: [PATCH 032/429] Update AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql --- .../AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql index 77fc29719f6..3e1cfdd6396 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql @@ -14,7 +14,7 @@ import cpp import semmle.code.cpp.valuenumbering.GlobalValueNumbering -from FunctionCall fc, AssignExpr expr, ArrayExpr exprarr +from StrlenCall fc, AssignExpr expr, ArrayExpr exprarr where exprarr = expr.getLValue() and expr.getRValue().getValue().toInt() = 0 and From 9a85b761a17b56d1c4b5a02e5cb26998fac590ff Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 12:46:10 +0300 Subject: [PATCH 033/429] Update test.c --- .../Security/CWE/CWE-788/semmle/tests/test.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c index 84487670bf7..ce07a2ddba2 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c @@ -10,30 +10,30 @@ void badFunc0(){ struct buffers buffAll; struct buffers * buffAll1; - buff1[strlen(buff1)]=0; - buffAll.buff1[strlen(buffAll.buff1)]=0; - buffAll.buff2[strlen(buffAll.buff2)]=0; - buffAll1->buff1[strlen(buffAll1->buff1)]=0; - buffAll1->buff2[strlen(buffAll1->buff2)]=0; - globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; - globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; - globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; - globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; + buff1[strlen(buff1)]=0; // BAD + buffAll.buff1[strlen(buffAll.buff1)]=0; // BAD + buffAll.buff2[strlen(buffAll.buff2)]=0; // BAD + buffAll1->buff1[strlen(buffAll1->buff1)]=0; // BAD + buffAll1->buff2[strlen(buffAll1->buff2)]=0; // BAD + globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; // BAD + globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; // BAD + globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; // BAD + globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; // BAD } void noBadFunc0(){ unsigned char buff1[12],buff1_c[12]; struct buffers buffAll,buffAll_c; struct buffers * buffAll1,*buffAll1_c; - buff1[strlen(buff1_c)]=0; - buffAll.buff1[strlen(buffAll_c.buff1)]=0; - buffAll.buff2[strlen(buffAll.buff1)]=0; - buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; - buffAll1->buff2[strlen(buffAll1->buff1)]=0; - globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; - globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; - globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; - globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; + buff1[strlen(buff1_c)]=0; // GOOD + buffAll.buff1[strlen(buffAll_c.buff1)]=0; // GOOD + buffAll.buff2[strlen(buffAll.buff1)]=0; // GOOD + buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; // GOOD + buffAll1->buff2[strlen(buffAll1->buff1)]=0; // GOOD + globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; // GOOD + globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; // GOOD + globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; // GOOD + globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; // GOOD } void goodFunc0(){ unsigned char buffer[12]; From 885d26805febf0b1fe7e253f6065f31f83291c03 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 12:47:51 +0300 Subject: [PATCH 034/429] Update AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected --- ...ocationAfterEndOfBufferUsingStrlen.expected | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected index 82d3e224993..c2f02dd203e 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected @@ -1,9 +1,9 @@ -| test.c:13:3:13:24 | ... = ... | use a different method to calculate the length. | -| test.c:14:3:14:40 | ... = ... | use a different method to calculate the length. | -| test.c:15:3:15:40 | ... = ... | use a different method to calculate the length. | -| test.c:16:3:16:44 | ... = ... | use a different method to calculate the length. | -| test.c:17:3:17:44 | ... = ... | use a different method to calculate the length. | -| test.c:18:3:18:48 | ... = ... | use a different method to calculate the length. | -| test.c:19:3:19:48 | ... = ... | use a different method to calculate the length. | -| test.c:20:3:20:50 | ... = ... | use a different method to calculate the length. | -| test.c:21:3:21:50 | ... = ... | use a different method to calculate the length. | +| test.c:13:3:13:24 | ... = ... | potential unsafe or redundant assignment. | +| test.c:14:3:14:40 | ... = ... | potential unsafe or redundant assignment. | +| test.c:15:3:15:40 | ... = ... | potential unsafe or redundant assignment. | +| test.c:16:3:16:44 | ... = ... | potential unsafe or redundant assignment. | +| test.c:17:3:17:44 | ... = ... | potential unsafe or redundant assignment. | +| test.c:18:3:18:48 | ... = ... | potential unsafe or redundant assignment. | +| test.c:19:3:19:48 | ... = ... | potential unsafe or redundant assignment. | +| test.c:20:3:20:50 | ... = ... | potential unsafe or redundant assignment. | +| test.c:21:3:21:50 | ... = ... | potential unsafe or redundant assignment. | From bdba7e14fe293225269ae2932a4cb539b453bedd Mon Sep 17 00:00:00 2001 From: intrigus Date: Wed, 27 Jan 2021 11:54:40 +0100 Subject: [PATCH 035/429] Java: Switch to data flow --- .../CWE/CWE-295/JxBrowserWithoutCertValidation.ql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql index 6aee64ed010..71a050a20ce 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql @@ -9,7 +9,7 @@ import java import semmle.code.java.security.Encryption -import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.DataFlow /* * This query is version specific to JxBrowser < 6.24. The version is indirectly detected. @@ -57,8 +57,8 @@ private class JxBrowserSafeLoadHandler extends RefType { } } -private class JxBrowserTaintTracking extends TaintTracking::Configuration { - JxBrowserTaintTracking() { this = "JxBrowserTaintTracking" } +private class JxBrowserFlowConfiguration extends DataFlow::Configuration { + JxBrowserFlowConfiguration() { this = "JxBrowserFlowConfiguration" } override predicate isSource(DataFlow::Node src) { exists(ClassInstanceExpr newJxBrowser | newJxBrowser.getConstructedType() instanceof JxBrowser | @@ -74,7 +74,7 @@ private class JxBrowserTaintTracking extends TaintTracking::Configuration { } } -from JxBrowserTaintTracking cfg, DataFlow::Node src +from JxBrowserFlowConfiguration cfg, DataFlow::Node src where cfg.isSource(src) and not cfg.hasFlow(src, _) and From d3e6e594b2b4efc1d81616cc8bfbe2f3e6aff7d5 Mon Sep 17 00:00:00 2001 From: intrigus Date: Wed, 27 Jan 2021 11:57:32 +0100 Subject: [PATCH 036/429] Java: Improve QLDoc --- .../Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql index 71a050a20ce..4046f4e9606 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql @@ -57,6 +57,10 @@ private class JxBrowserSafeLoadHandler extends RefType { } } +/** + * Models flow from the source `new Browser()` to a sink `browser.setLoadHandler(loadHandler)` where `loadHandler` + * has been determined to be safe. + */ private class JxBrowserFlowConfiguration extends DataFlow::Configuration { JxBrowserFlowConfiguration() { this = "JxBrowserFlowConfiguration" } From 8737c1442b9f52d5f1c3a29e2762db0b850873eb Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 14:48:23 +0300 Subject: [PATCH 037/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.cpp --- ...ctingAndHandlingMemoryAllocationErrors.cpp | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp index 6fc3bc2f893..0232fc131eb 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp @@ -1,32 +1,31 @@ -// BAD: no memory allocation errors are detected -void f(const int *array, std::size_t size) noexcept { - int *copy = new int[size]; - std::memcpy(copy, array, size * sizeof(*copy)); - // ... - delete [] copy; +// BAD: on memory allocation error, the program terminates. +void badFunction(const int *source, std::size_t length) noexcept { + int * dest = new int[length]; + std::memset(dest, 0, length); +// .. } -// GOOD: memory allocation errors are detected -void f(const int *array, std::size_t size) noexcept { - int *copy; +// GOOD: memory allocation error will be handled. +void goodFunction(const int *source, std::size_t length) noexcept { try { - copy = new int[size]; - } catch(std::bad_alloc) { - // Handle error - return; - } - // At this point, copy has been initialized to allocated memory - std::memcpy(copy, array, size * sizeof(*copy)); - // ... - delete [] copy; + int * dest = new int[length]; + } catch(std::bad_alloc) + std::memset(dest, 0, length); +// .. } -// GOOD: memory allocation errors are detected -void f(const int *array, std::size_t size) noexcept { - int *copy = new (std::nothrow) int[size]; - if (!copy) { - // Handle error - return; - } - std::memcpy(copy, array, size * sizeof(*copy)); - // ... - delete [] copy; +// BAD: memory allocation error will not be handled. +void badFunction(const int *source, std::size_t length) noexcept { + try { + int * dest = new (std::nothrow) int[length]; + } catch(std::bad_alloc) + std::memset(dest, 0, length); +// .. +} +// GOOD: memory allocation error will be handled. +void goodFunction(const int *source, std::size_t length) noexcept { + int * dest = new (std::nothrow) int[length]; + if (!dest) { + return; + } + std::memset(dest, 0, length); +// .. } From bec00643968bad1ae39d53e0256111187569b907 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 14:54:47 +0300 Subject: [PATCH 038/429] Update test.cpp --- .../CWE/CWE-570/semmle/tests/test.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp index 6f03f896024..e4aa8cf2976 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-570/semmle/tests/test.cpp @@ -20,14 +20,14 @@ void* operator new[]( std::size_t count, const std::nothrow_t& tag ); void badNew_0_0() { while (true) { - new int[100]; - if(!(new int[100])) + new int[100]; // BAD [NOT DETECTED] + if(!(new int[100])) // BAD [NOT DETECTED] return; } } void badNew_0_1() { - int * i = new int[100]; + int * i = new int[100]; // BAD if(i == 0) return; if(!i) @@ -35,7 +35,7 @@ void badNew_0_1() if(i == NULL) return; int * j; - j = new int[100]; + j = new int[100]; // BAD if(j == 0) return; if(!j) @@ -47,10 +47,10 @@ void badNew_1_0() { try { while (true) { - new(std::nothrow) int[100]; - int* p = new(std::nothrow) int[100]; + new(std::nothrow) int[100]; // BAD + int* p = new(std::nothrow) int[100]; // BAD int* p1; - p1 = new(std::nothrow) int[100]; + p1 = new(std::nothrow) int[100]; // BAD } } catch (const exception &){//const std::bad_alloc& e) { // std::cout << e.what() << '\n'; @@ -59,8 +59,8 @@ void badNew_1_0() void badNew_1_1() { while (true) { - int* p = new(std::nothrow) int[100]; - new(std::nothrow) int[100]; + int* p = new(std::nothrow) int[100]; // BAD [NOT DETECTED] + new(std::nothrow) int[100]; // BAD [NOT DETECTED] } } @@ -68,7 +68,7 @@ void goodNew_0_0() { try { while (true) { - new int[100]; + new int[100]; // GOOD } } catch (const exception &){//const std::bad_alloc& e) { // std::cout << e.what() << '\n'; @@ -78,18 +78,18 @@ void goodNew_0_0() void goodNew_1_0() { while (true) { - int* p = new(std::nothrow) int[100]; + int* p = new(std::nothrow) int[100]; // GOOD if (p == nullptr) { // std::cout << "Allocation returned nullptr\n"; break; } int* p1; - p1 = new(std::nothrow) int[100]; + p1 = new(std::nothrow) int[100]; // GOOD if (p1 == nullptr) { // std::cout << "Allocation returned nullptr\n"; break; } - if (new(std::nothrow) int[100] == nullptr) { + if (new(std::nothrow) int[100] == nullptr) { // GOOD // std::cout << "Allocation returned nullptr\n"; break; } From 25de82c78cd5c19fd1957a8926ba7e395edf2815 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 15:05:01 +0300 Subject: [PATCH 039/429] Apply suggestions from code review Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp index 4b7941a5846..7be7fcd5b35 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp @@ -3,18 +3,18 @@ "qhelp.dtd"> -

    when using the new operator to allocate memory, you need to pay attention to the different way of detecting errors. so ::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. the programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    +

    When using the new operator to allocate memory, you need to pay attention to the different ways of detecting errors. ::operator new(std::size_t) throws an exception on error, whereas ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. The programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    Loss of detection probably refers to use cases where memory allocation using your own solutions with strong nesting. It is also possible when using a buffer in the form of fields of different structures with the same names.

    -

    We recommend using the error detection method, depending on the selected memory allocation method..

    +

    Use the correct error detection method corresponding with the memory allocation.

    -

    The following file demonstrates various approaches to detecting memory allocation errors using the new operator.

    +

    The following example demonstrates various approaches to detecting memory allocation errors using the new operator.

    From 5d163b4c1575115a5f1c14eba0145b74908ee292 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 15:05:58 +0300 Subject: [PATCH 040/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp | 2 -- 1 file changed, 2 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp index 7be7fcd5b35..c3e543a1b58 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp @@ -5,8 +5,6 @@

    When using the new operator to allocate memory, you need to pay attention to the different ways of detecting errors. ::operator new(std::size_t) throws an exception on error, whereas ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. The programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    -

    Loss of detection probably refers to use cases where memory allocation using your own solutions with strong nesting. It is also possible when using a buffer in the form of fields of different structures with the same names.

    -
    From 16d058f49865acb62d36c1a9b1af0aa6810d9eac Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 15:06:57 +0300 Subject: [PATCH 041/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.ql --- .../CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index 383c8a1f128..c32c14c1dd0 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -2,7 +2,6 @@ * @name Сonfusion In Detecting And Handling Memory Allocation Errors * @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. * --the programmer can get confused when check the error that occurs when allocating memory incorrectly. - * --Making a call of this type may result in a zero byte being written just outside the buffer. * @kind problem * @id cpp/detect-and-handle-memory-allocation-errors * @problem.severity warning From bdfdcbd6735a841c4329a26b15bc4130c10e8f67 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Wed, 27 Jan 2021 15:48:18 +0300 Subject: [PATCH 042/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.ql --- ...rongInDetectingAndHandlingMemoryAllocationErrors.ql | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index c32c14c1dd0..e165d61985b 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -44,14 +44,8 @@ class WrongCheckErrorOperatorNew extends FunctionCall { * Holds if handler `try ... catch` exists. */ predicate isExistsTryCatchBlock() { - exists(TryStmt tb, AssignExpr aex, Initializer it | - tb.getAChild*() = exp - or - exp = it.getExpr() and - tb.getAChild*().(DeclStmt).getADeclaration() = it.getDeclaration() - or - aex.getAChild*() = exp and - tb.getAChild*().(AssignExpr) = aex + exists(TryStmt ts | + this.getEnclosingStmt() = ts.getStmt().getAChild*() ) } From 6a93099b645e32e7598999ddbcf0303f65e657fa Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 28 Jan 2021 03:02:53 +0000 Subject: [PATCH 043/429] Simplify the query and update qldoc --- .../experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp | 2 +- .../src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp index 9241b52cf19..ee4afabbed6 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp @@ -26,7 +26,7 @@
  • Oracle: - Simple authentication consists of sending the LDAP server the fully qualified DN of the client (user) and the client's clear-text password + Simple authentication
  • diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 602dae21ad7..9563c755410 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -202,13 +202,11 @@ where sink.getNode().asExpr() = va and exists(BasicAuthFlowConfig bc, DataFlow::PathNode source2, DataFlow::PathNode sink2 | bc.hasFlowPath(source2, sink2) and - source2.getNode().asExpr().(CompileTimeConstantExpr).getStringValue() = "simple" and sink2.getNode().asExpr() = va ) and not exists(SSLFlowConfig sc, DataFlow::PathNode source3, DataFlow::PathNode sink3 | sc.hasFlowPath(source3, sink3) and - source3.getNode().asExpr().(CompileTimeConstantExpr).getStringValue() = "ssl" and - sink3.getNode().asExpr() = va.getVariable().getAnAccess() + sink3.getNode().asExpr() = va ) select sink.getNode(), source, sink, "Insecure LDAP authentication from $@.", source.getNode(), "LDAP connection string" From cfc950f8039ca780b87a6889b2913e6702961b4e Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Thu, 7 Jan 2021 21:18:51 +0000 Subject: [PATCH 044/429] Query for weak encryption: Insufficient key size --- .../CWE/CWE-326/InsufficientKeySize.java | 37 +++++ .../CWE/CWE-326/InsufficientKeySize.qhelp | 33 ++++ .../CWE/CWE-326/InsufficientKeySize.ql | 155 ++++++++++++++++++ .../semmle/code/java/security/Encryption.qll | 12 ++ .../CWE-326/InsufficientKeySize.expected | 4 + .../security/CWE-326/InsufficientKeySize.java | 41 +++++ .../CWE-326/InsufficientKeySize.qlref | 1 + 7 files changed, 283 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql create mode 100644 java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java new file mode 100644 index 00000000000..6ccf025c244 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java @@ -0,0 +1,37 @@ +public class InsufficientKeySize { + public void CryptoMethod() { + KeyGenerator keyGen1 = KeyGenerator.getInstance("AES"); + // BAD: Key size is less than 128 + keyGen1.init(64); + + KeyGenerator keyGen2 = KeyGenerator.getInstance("AES"); + // GOOD: Key size is no less than 128 + keyGen2.init(128); + + KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA"); + // BAD: Key size is less than 2048 + keyPairGen1.initialize(1024); + + KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA"); + // GOOD: Key size is no less than 2048 + keyPairGen2.initialize(2048); + + KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA"); + // BAD: Key size is less than 2048 + keyPairGen3.initialize(1024); + + KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA"); + // GOOD: Key size is no less than 2048 + keyPairGen4.initialize(2048); + + KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1"); + keyPairGen5.initialize(ecSpec1); + + KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC"); + // GOOD: Key size is no less than 224 + ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); + keyPairGen6.initialize(ecSpec2); + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp new file mode 100644 index 00000000000..8de21f1c90a --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp @@ -0,0 +1,33 @@ + + + +

    This rule finds uses of encryption algorithms with too small a key size. Encryption algorithms +are vulnerable to brute force attack when too small a key size is used.

    +
    + + +

    The key should be at least 2048-bit long when using RSA and DSA encryption, 224-bit long when using EC encryption, and 128-bit long when using +symmetric encryption.

    +
    + + + +
  • + Wikipedia. + Key size +
  • +
  • + SonarSource. + Cryptographic keys should be robust +
  • +
  • + CWE. + CWE-326: Inadequate Encryption Strength +
  • +
  • + C# implementation of CodeQL + codeql/csharp/ql/src/Security Features/InsufficientKeySize.ql +
  • + +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql new file mode 100644 index 00000000000..882d997f1b8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -0,0 +1,155 @@ +/** + * @name Weak encryption: Insufficient key size + * @description Finds uses of encryption algorithms with too small a key size + * @kind problem + * @id java/insufficient-key-size + * @tags security + * external/cwe/cwe-326 + */ + +import java +import semmle.code.java.security.Encryption +import semmle.code.java.dataflow.TaintTracking + +/** The Java class `javax.crypto.KeyGenerator`. */ +class KeyGenerator extends RefType { + KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") } +} + +/** The Java class `javax.crypto.KeyGenerator`. */ +class KeyPairGenerator extends RefType { + KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") } +} + +/** The Java class `java.security.spec.ECGenParameterSpec`. */ +class ECGenParameterSpec extends RefType { + ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") } +} + +/** The `init` method declared in `javax.crypto.KeyGenerator`. */ +class KeyGeneratorInitMethod extends Method { + KeyGeneratorInitMethod() { + getDeclaringType() instanceof KeyGenerator and + hasName("init") + } +} + +/** The `initialize` method declared in `java.security.KeyPairGenerator`. */ +class KeyPairGeneratorInitMethod extends Method { + KeyPairGeneratorInitMethod() { + getDeclaringType() instanceof KeyPairGenerator and + hasName("initialize") + } +} + +/** Taint configuration tracking flow from a key generator to a `init` method call. */ +class CryptoKeyGeneratorConfiguration extends TaintTracking::Configuration { + CryptoKeyGeneratorConfiguration() { this = "CryptoKeyGeneratorConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(JavaxCryptoKeyGenerator jcg | jcg = source.asExpr()) + } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | + ma.getMethod() instanceof KeyGeneratorInitMethod and + sink.asExpr() = ma.getQualifier() + ) + } +} + +/** Taint configuration tracking flow from a keypair generator to a `initialize` method call. */ +class KeyPairGeneratorConfiguration extends TaintTracking::Configuration { + KeyPairGeneratorConfiguration() { this = "KeyPairGeneratorConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(JavaSecurityKeyPairGenerator jkg | jkg = source.asExpr()) + } + + override predicate isSink(DataFlow::Node sink) { + exists(MethodAccess ma | + ma.getMethod() instanceof KeyPairGeneratorInitMethod and + sink.asExpr() = ma.getQualifier() + ) + } +} + +/** Holds if an AES `KeyGenerator` is initialized with an insufficient key size. */ +predicate incorrectUseOfAES(MethodAccess ma, string msg) { + ma.getMethod() instanceof KeyGeneratorInitMethod and + exists( + JavaxCryptoKeyGenerator jcg, CryptoKeyGeneratorConfiguration cc, DataFlow::PathNode source, + DataFlow::PathNode dest + | + jcg.getAlgoSpec().(StringLiteral).getValue() = "AES" and + source.getNode().asExpr() = jcg and + dest.getNode().asExpr() = ma.getQualifier() and + cc.hasFlowPath(source, dest) + ) and + ma.getArgument(0).(IntegerLiteral).getIntValue() < 128 and + msg = "Key size should be at least 128 bits for AES encryption." +} + +/** Holds if a DSA `KeyPairGenerator` is initialized with an insufficient key size. */ +predicate incorrectUseOfDSA(MethodAccess ma, string msg) { + ma.getMethod() instanceof KeyPairGeneratorInitMethod and + exists( + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, + DataFlow::PathNode dest + | + jpg.getAlgoSpec().(StringLiteral).getValue() = "DSA" and + source.getNode().asExpr() = jpg and + dest.getNode().asExpr() = ma.getQualifier() and + kc.hasFlowPath(source, dest) + ) and + ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and + msg = "Key size should be at least 2048 bits for DSA encryption." +} + +/** Holds if a RSA `KeyPairGenerator` is initialized with an insufficient key size. */ +predicate incorrectUseOfRSA(MethodAccess ma, string msg) { + ma.getMethod() instanceof KeyPairGeneratorInitMethod and + exists( + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, + DataFlow::PathNode dest + | + jpg.getAlgoSpec().(StringLiteral).getValue() = "RSA" and + source.getNode().asExpr() = jpg and + dest.getNode().asExpr() = ma.getQualifier() and + kc.hasFlowPath(source, dest) + ) and + ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and + msg = "Key size should be at least 2048 bits for RSA encryption." +} + +/** Holds if an EC `KeyPairGenerator` is initialized with an insufficient key size. */ +predicate incorrectUseOfEC(MethodAccess ma, string msg) { + ma.getMethod() instanceof KeyPairGeneratorInitMethod and + exists( + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, + DataFlow::PathNode dest, ClassInstanceExpr cie + | + jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and //ECC variants such as ECDH and ECDSA + source.getNode().asExpr() = jpg and + dest.getNode().asExpr() = ma.getQualifier() and + kc.hasFlowPath(source, dest) and + exists(VariableAssign va | + ma.getArgument(0).(VarAccess).getVariable() = va.getDestVar() and + va.getSource() = cie and + cie.getArgument(0) + .(StringLiteral) + .getRepresentedString() + .regexpCapture(".*[a-zA-Z]+([0-9]+)[a-zA-Z]+.*", 1) + .toInt() < 224 + ) + ) and + msg = "Key size should be at least 224 bits for EC encryption." +} + +from Expr e, string msg +where + incorrectUseOfAES(e, msg) or + incorrectUseOfDSA(e, msg) or + incorrectUseOfRSA(e, msg) or + incorrectUseOfEC(e, msg) +select e, msg diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index d48a5c6c715..b133fd3c523 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -304,3 +304,15 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec { override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) } } + +/** Method call to the Java class `java.security.KeyPairGenerator`. */ +class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec { + JavaSecurityKeyPairGenerator() { + exists(Method m | m.getAReference() = this | + m.getDeclaringType().getQualifiedName() = "java.security.KeyPairGenerator" and + m.getName() = "getInstance" + ) + } + + override Expr getAlgoSpec() { result = this.(MethodAccess).getArgument(0) } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected new file mode 100644 index 00000000000..b47469aed5d --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected @@ -0,0 +1,4 @@ +| InsufficientKeySize.java:9:9:9:24 | init(...) | Key size should be at least 128 bits for AES encryption. | +| InsufficientKeySize.java:17:9:17:36 | initialize(...) | Key size should be at least 2048 bits for RSA encryption. | +| InsufficientKeySize.java:25:9:25:36 | initialize(...) | Key size should be at least 2048 bits for DSA encryption. | +| InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java new file mode 100644 index 00000000000..13f74b6fac3 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java @@ -0,0 +1,41 @@ +import java.security.KeyPairGenerator; +import java.security.spec.ECGenParameterSpec; +import javax.crypto.KeyGenerator; + +public class InsufficientKeySize { + public void CryptoMethod() { + KeyGenerator keyGen1 = KeyGenerator.getInstance("AES"); + // BAD: Key size is less than 128 + keyGen1.init(64); + + KeyGenerator keyGen2 = KeyGenerator.getInstance("AES"); + // GOOD: Key size is no less than 128 + keyGen2.init(128); + + KeyPairGenerator keyPairGen1 = KeyPairGenerator.getInstance("RSA"); + // BAD: Key size is less than 2048 + keyPairGen1.initialize(1024); + + KeyPairGenerator keyPairGen2 = KeyPairGenerator.getInstance("RSA"); + // GOOD: Key size is no less than 2048 + keyPairGen2.initialize(2048); + + KeyPairGenerator keyPairGen3 = KeyPairGenerator.getInstance("DSA"); + // BAD: Key size is less than 2048 + keyPairGen3.initialize(1024); + + KeyPairGenerator keyPairGen4 = KeyPairGenerator.getInstance("DSA"); + // GOOD: Key size is no less than 2048 + keyPairGen4.initialize(2048); + + KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1"); + keyPairGen5.initialize(ecSpec1); + + KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC"); + // GOOD: Key size is no less than 224 + ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); + keyPairGen6.initialize(ecSpec2); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.qlref b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.qlref new file mode 100644 index 00000000000..2b35cd6921e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-326/InsufficientKeySize.ql \ No newline at end of file From cbaee937d0ab8962278be494e36eaad5ab24693f Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 8 Jan 2021 21:56:34 +0000 Subject: [PATCH 045/429] Optimize the query --- .../CWE/CWE-326/InsufficientKeySize.qhelp | 6 +- .../CWE/CWE-326/InsufficientKeySize.ql | 91 ++++++++----------- .../semmle/code/java/security/Encryption.qll | 14 ++- .../CWE-326/InsufficientKeySize.expected | 4 + .../security/CWE-326/InsufficientKeySize.java | 21 ++++- 5 files changed, 77 insertions(+), 59 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp index 8de21f1c90a..10ec6adc9df 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp @@ -6,7 +6,7 @@ are vulnerable to brute force attack when too small a key size is used.

    -

    The key should be at least 2048-bit long when using RSA and DSA encryption, 224-bit long when using EC encryption, and 128-bit long when using +

    The key should be at least 2048 bits long when using RSA and DSA encryption, 224 bits long when using EC encryption, and 128 bits long when using symmetric encryption.

    @@ -24,10 +24,6 @@ symmetric encryption.

    CWE. CWE-326: Inadequate Encryption Strength -
  • - C# implementation of CodeQL - codeql/csharp/ql/src/Security Features/InsufficientKeySize.ql -
  • \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql index 882d997f1b8..df265f267f7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -11,16 +11,6 @@ import java import semmle.code.java.security.Encryption import semmle.code.java.dataflow.TaintTracking -/** The Java class `javax.crypto.KeyGenerator`. */ -class KeyGenerator extends RefType { - KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") } -} - -/** The Java class `javax.crypto.KeyGenerator`. */ -class KeyPairGenerator extends RefType { - KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") } -} - /** The Java class `java.security.spec.ECGenParameterSpec`. */ class ECGenParameterSpec extends RefType { ECGenParameterSpec() { this.hasQualifiedName("java.security.spec", "ECGenParameterSpec") } @@ -42,9 +32,19 @@ class KeyPairGeneratorInitMethod extends Method { } } +/** Returns the key size in the EC algorithm string */ +bindingset[algorithm] +int getECKeySize(string algorithm) { + algorithm.matches("sec%") and // specification such as "secp256r1" + result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt() + or + algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2" + result = algorithm.regexpCapture("X9.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() +} + /** Taint configuration tracking flow from a key generator to a `init` method call. */ -class CryptoKeyGeneratorConfiguration extends TaintTracking::Configuration { - CryptoKeyGeneratorConfiguration() { this = "CryptoKeyGeneratorConfiguration" } +class KeyGeneratorInitConfiguration extends TaintTracking::Configuration { + KeyGeneratorInitConfiguration() { this = "KeyGeneratorInitConfiguration" } override predicate isSource(DataFlow::Node source) { exists(JavaxCryptoKeyGenerator jcg | jcg = source.asExpr()) @@ -59,8 +59,8 @@ class CryptoKeyGeneratorConfiguration extends TaintTracking::Configuration { } /** Taint configuration tracking flow from a keypair generator to a `initialize` method call. */ -class KeyPairGeneratorConfiguration extends TaintTracking::Configuration { - KeyPairGeneratorConfiguration() { this = "KeyPairGeneratorConfiguration" } +class KeyPairGeneratorInitConfiguration extends TaintTracking::Configuration { + KeyPairGeneratorInitConfiguration() { this = "KeyPairGeneratorInitConfiguration" } override predicate isSource(DataFlow::Node source) { exists(JavaSecurityKeyPairGenerator jkg | jkg = source.asExpr()) @@ -75,10 +75,10 @@ class KeyPairGeneratorConfiguration extends TaintTracking::Configuration { } /** Holds if an AES `KeyGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfAES(MethodAccess ma, string msg) { +predicate hasShortAESKey(MethodAccess ma, string msg) { ma.getMethod() instanceof KeyGeneratorInitMethod and exists( - JavaxCryptoKeyGenerator jcg, CryptoKeyGeneratorConfiguration cc, DataFlow::PathNode source, + JavaxCryptoKeyGenerator jcg, KeyGeneratorInitConfiguration cc, DataFlow::PathNode source, DataFlow::PathNode dest | jcg.getAlgoSpec().(StringLiteral).getValue() = "AES" and @@ -90,66 +90,55 @@ predicate incorrectUseOfAES(MethodAccess ma, string msg) { msg = "Key size should be at least 128 bits for AES encryption." } -/** Holds if a DSA `KeyPairGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfDSA(MethodAccess ma, string msg) { +/** Holds if an asymmetric `KeyPairGenerator` is initialized with an insufficient key size. */ +bindingset[type] +predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { ma.getMethod() instanceof KeyPairGeneratorInitMethod and exists( - JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, - DataFlow::PathNode dest + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc, + DataFlow::PathNode source, DataFlow::PathNode dest | - jpg.getAlgoSpec().(StringLiteral).getValue() = "DSA" and + jpg.getAlgoSpec().(StringLiteral).getValue() = type and source.getNode().asExpr() = jpg and dest.getNode().asExpr() = ma.getQualifier() and kc.hasFlowPath(source, dest) ) and ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and - msg = "Key size should be at least 2048 bits for DSA encryption." + msg = "Key size should be at least 2048 bits for " + type + " encryption." +} + +/** Holds if a DSA `KeyPairGenerator` is initialized with an insufficient key size. */ +predicate hasShortDSAKeyPair(MethodAccess ma, string msg) { + hasShortAsymmetricKeyPair(ma, msg, "DSA") } /** Holds if a RSA `KeyPairGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfRSA(MethodAccess ma, string msg) { - ma.getMethod() instanceof KeyPairGeneratorInitMethod and - exists( - JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, - DataFlow::PathNode dest - | - jpg.getAlgoSpec().(StringLiteral).getValue() = "RSA" and - source.getNode().asExpr() = jpg and - dest.getNode().asExpr() = ma.getQualifier() and - kc.hasFlowPath(source, dest) - ) and - ma.getArgument(0).(IntegerLiteral).getIntValue() < 2048 and - msg = "Key size should be at least 2048 bits for RSA encryption." +predicate hasShortRSAKeyPair(MethodAccess ma, string msg) { + hasShortAsymmetricKeyPair(ma, msg, "RSA") } /** Holds if an EC `KeyPairGenerator` is initialized with an insufficient key size. */ -predicate incorrectUseOfEC(MethodAccess ma, string msg) { +predicate hasShortECKeyPair(MethodAccess ma, string msg) { ma.getMethod() instanceof KeyPairGeneratorInitMethod and exists( - JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorConfiguration kc, DataFlow::PathNode source, - DataFlow::PathNode dest, ClassInstanceExpr cie + JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc, + DataFlow::PathNode source, DataFlow::PathNode dest, ClassInstanceExpr cie | jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and //ECC variants such as ECDH and ECDSA source.getNode().asExpr() = jpg and dest.getNode().asExpr() = ma.getQualifier() and kc.hasFlowPath(source, dest) and - exists(VariableAssign va | - ma.getArgument(0).(VarAccess).getVariable() = va.getDestVar() and - va.getSource() = cie and - cie.getArgument(0) - .(StringLiteral) - .getRepresentedString() - .regexpCapture(".*[a-zA-Z]+([0-9]+)[a-zA-Z]+.*", 1) - .toInt() < 224 - ) + DataFlow::localExprFlow(cie, ma.getArgument(0)) and + ma.getArgument(0).getType() instanceof ECGenParameterSpec and + getECKeySize(cie.getArgument(0).(StringLiteral).getRepresentedString()) < 224 ) and msg = "Key size should be at least 224 bits for EC encryption." } from Expr e, string msg where - incorrectUseOfAES(e, msg) or - incorrectUseOfDSA(e, msg) or - incorrectUseOfRSA(e, msg) or - incorrectUseOfEC(e, msg) + hasShortAESKey(e, msg) or + hasShortDSAKeyPair(e, msg) or + hasShortRSAKeyPair(e, msg) or + hasShortECKeyPair(e, msg) select e, msg diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index b133fd3c523..9c10569d8c1 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -38,6 +38,16 @@ class HostnameVerifier extends RefType { HostnameVerifier() { hasQualifiedName("javax.net.ssl", "HostnameVerifier") } } +/** The Java class `javax.crypto.KeyGenerator`. */ +class KeyGenerator extends RefType { + KeyGenerator() { this.hasQualifiedName("javax.crypto", "KeyGenerator") } +} + +/** The Java class `java.security.KeyPairGenerator`. */ +class KeyPairGenerator extends RefType { + KeyPairGenerator() { this.hasQualifiedName("java.security", "KeyPairGenerator") } +} + /** The `verify` method of the class `javax.net.ssl.HostnameVerifier`. */ class HostnameVerifierVerify extends Method { HostnameVerifierVerify() { @@ -248,7 +258,7 @@ class JavaxCryptoSecretKey extends JavaxCryptoAlgoSpec { class JavaxCryptoKeyGenerator extends JavaxCryptoAlgoSpec { JavaxCryptoKeyGenerator() { exists(Method m | m.getAReference() = this | - m.getDeclaringType().getQualifiedName() = "javax.crypto.KeyGenerator" and + m.getDeclaringType() instanceof KeyGenerator and m.getName() = "getInstance" ) } @@ -309,7 +319,7 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec { class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec { JavaSecurityKeyPairGenerator() { exists(Method m | m.getAReference() = this | - m.getDeclaringType().getQualifiedName() = "java.security.KeyPairGenerator" and + m.getDeclaringType() instanceof KeyPairGenerator and m.getName() = "getInstance" ) } diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected index b47469aed5d..f350495d28f 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected @@ -2,3 +2,7 @@ | InsufficientKeySize.java:17:9:17:36 | initialize(...) | Key size should be at least 2048 bits for RSA encryption. | | InsufficientKeySize.java:25:9:25:36 | initialize(...) | Key size should be at least 2048 bits for DSA encryption. | | InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:38:9:38:67 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:48:9:48:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:53:9:53:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:58:9:58:40 | initialize(...) | Key size should be at least 224 bits for EC encryption. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java index 13f74b6fac3..80d49cdf5f1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java @@ -34,8 +34,27 @@ public class InsufficientKeySize { keyPairGen5.initialize(ecSpec1); KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + keyPairGen6.initialize(new ECGenParameterSpec("secp112r1")); + + KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC"); // GOOD: Key size is no less than 224 ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); - keyPairGen6.initialize(ecSpec2); + keyPairGen7.initialize(ecSpec2); + + KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2"); + keyPairGen8.initialize(ecSpec3); + + KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3"); + keyPairGen9.initialize(ecSpec4); + + KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 224 + ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1"); + keyPairGen10.initialize(ecSpec5); } } From 058f3af4b21bfe3dec4bdcbb84f3bd26c5830dca Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Sat, 9 Jan 2021 13:48:29 +0000 Subject: [PATCH 046/429] Refactor the hasShortSymmetricKey method --- .../Security/CWE/CWE-326/InsufficientKeySize.ql | 14 +++++++++----- .../security/CWE-326/InsufficientKeySize.java | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql index df265f267f7..169e1e58a69 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -39,7 +39,7 @@ int getECKeySize(string algorithm) { result = algorithm.regexpCapture("sec[p|t](\\d+)[a-zA-Z].*", 1).toInt() or algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2" - result = algorithm.regexpCapture("X9.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() + result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() } /** Taint configuration tracking flow from a key generator to a `init` method call. */ @@ -74,22 +74,26 @@ class KeyPairGeneratorInitConfiguration extends TaintTracking::Configuration { } } -/** Holds if an AES `KeyGenerator` is initialized with an insufficient key size. */ -predicate hasShortAESKey(MethodAccess ma, string msg) { +/** Holds if a symmetric `KeyGenerator` is initialized with an insufficient key size. */ +bindingset[type] +predicate hasShortSymmetricKey(MethodAccess ma, string msg, string type) { ma.getMethod() instanceof KeyGeneratorInitMethod and exists( JavaxCryptoKeyGenerator jcg, KeyGeneratorInitConfiguration cc, DataFlow::PathNode source, DataFlow::PathNode dest | - jcg.getAlgoSpec().(StringLiteral).getValue() = "AES" and + jcg.getAlgoSpec().(StringLiteral).getValue() = type and source.getNode().asExpr() = jcg and dest.getNode().asExpr() = ma.getQualifier() and cc.hasFlowPath(source, dest) ) and ma.getArgument(0).(IntegerLiteral).getIntValue() < 128 and - msg = "Key size should be at least 128 bits for AES encryption." + msg = "Key size should be at least 128 bits for " + type + " encryption." } +/** Holds if an AES `KeyGenerator` is initialized with an insufficient key size. */ +predicate hasShortAESKey(MethodAccess ma, string msg) { hasShortSymmetricKey(ma, msg, "AES") } + /** Holds if an asymmetric `KeyPairGenerator` is initialized with an insufficient key size. */ bindingset[type] predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java index 80d49cdf5f1..45b7c610df1 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java @@ -56,5 +56,10 @@ public class InsufficientKeySize { // BAD: Key size is less than 224 ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1"); keyPairGen10.initialize(ecSpec5); + + KeyPairGenerator keyPairGen11 = KeyPairGenerator.getInstance("EC"); + // GOOD: Key size is no less than 224 + ECGenParameterSpec ecSpec6 = new ECGenParameterSpec("X9.62 c2tnb359v1"); + keyPairGen11.initialize(ecSpec6); } } From 2ac7b4bab42c4146fb9f629291d049efa43d52e8 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 11 Jan 2021 12:59:00 +0000 Subject: [PATCH 047/429] Update qldoc --- .../Security/CWE/CWE-326/InsufficientKeySize.ql | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql index 169e1e58a69..c925ef0a966 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -74,7 +74,7 @@ class KeyPairGeneratorInitConfiguration extends TaintTracking::Configuration { } } -/** Holds if a symmetric `KeyGenerator` is initialized with an insufficient key size. */ +/** Holds if a symmetric `KeyGenerator` implementing encryption algorithm `type` and initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ bindingset[type] predicate hasShortSymmetricKey(MethodAccess ma, string msg, string type) { ma.getMethod() instanceof KeyGeneratorInitMethod and @@ -91,10 +91,10 @@ predicate hasShortSymmetricKey(MethodAccess ma, string msg, string type) { msg = "Key size should be at least 128 bits for " + type + " encryption." } -/** Holds if an AES `KeyGenerator` is initialized with an insufficient key size. */ +/** Holds if an AES `KeyGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ predicate hasShortAESKey(MethodAccess ma, string msg) { hasShortSymmetricKey(ma, msg, "AES") } -/** Holds if an asymmetric `KeyPairGenerator` is initialized with an insufficient key size. */ +/** Holds if an asymmetric `KeyPairGenerator` implementing encryption algorithm `type` and initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ bindingset[type] predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { ma.getMethod() instanceof KeyPairGeneratorInitMethod and @@ -111,24 +111,24 @@ predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { msg = "Key size should be at least 2048 bits for " + type + " encryption." } -/** Holds if a DSA `KeyPairGenerator` is initialized with an insufficient key size. */ +/** Holds if a DSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ predicate hasShortDSAKeyPair(MethodAccess ma, string msg) { hasShortAsymmetricKeyPair(ma, msg, "DSA") } -/** Holds if a RSA `KeyPairGenerator` is initialized with an insufficient key size. */ +/** Holds if a RSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ predicate hasShortRSAKeyPair(MethodAccess ma, string msg) { hasShortAsymmetricKeyPair(ma, msg, "RSA") } -/** Holds if an EC `KeyPairGenerator` is initialized with an insufficient key size. */ +/** Holds if an EC `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ predicate hasShortECKeyPair(MethodAccess ma, string msg) { ma.getMethod() instanceof KeyPairGeneratorInitMethod and exists( JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc, DataFlow::PathNode source, DataFlow::PathNode dest, ClassInstanceExpr cie | - jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and //ECC variants such as ECDH and ECDSA + jpg.getAlgoSpec().(StringLiteral).getValue().matches("EC%") and // ECC variants such as ECDH and ECDSA source.getNode().asExpr() = jpg and dest.getNode().asExpr() = ma.getQualifier() and kc.hasFlowPath(source, dest) and From ab7d257569907903cf6731fa10f64c348ad25b46 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 15 Jan 2021 13:11:32 +0000 Subject: [PATCH 048/429] Add more cases and change EC to 256 bits --- .../CWE/CWE-326/InsufficientKeySize.ql | 11 +++-- .../CWE-326/InsufficientKeySize.expected | 13 +++--- .../security/CWE-326/InsufficientKeySize.java | 42 +++++++++++++++---- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql index c925ef0a966..41242a44805 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.ql @@ -40,6 +40,9 @@ int getECKeySize(string algorithm) { or algorithm.matches("X9.62%") and //specification such as "X9.62 prime192v2" result = algorithm.regexpCapture("X9\\.62 .*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() + or + (algorithm.matches("prime%") or algorithm.matches("c2tnb%")) and //specification such as "prime192v2" + result = algorithm.regexpCapture(".*[a-zA-Z](\\d+)[a-zA-Z].*", 1).toInt() } /** Taint configuration tracking flow from a key generator to a `init` method call. */ @@ -102,7 +105,7 @@ predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { JavaSecurityKeyPairGenerator jpg, KeyPairGeneratorInitConfiguration kc, DataFlow::PathNode source, DataFlow::PathNode dest | - jpg.getAlgoSpec().(StringLiteral).getValue() = type and + jpg.getAlgoSpec().(StringLiteral).getValue().toUpperCase() = type and source.getNode().asExpr() = jpg and dest.getNode().asExpr() = ma.getQualifier() and kc.hasFlowPath(source, dest) @@ -113,7 +116,7 @@ predicate hasShortAsymmetricKeyPair(MethodAccess ma, string msg, string type) { /** Holds if a DSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ predicate hasShortDSAKeyPair(MethodAccess ma, string msg) { - hasShortAsymmetricKeyPair(ma, msg, "DSA") + hasShortAsymmetricKeyPair(ma, msg, "DSA") or hasShortAsymmetricKeyPair(ma, msg, "DH") } /** Holds if a RSA `KeyPairGenerator` initialized by `ma` uses an insufficient key size. `msg` provides a human-readable description of the problem. */ @@ -134,9 +137,9 @@ predicate hasShortECKeyPair(MethodAccess ma, string msg) { kc.hasFlowPath(source, dest) and DataFlow::localExprFlow(cie, ma.getArgument(0)) and ma.getArgument(0).getType() instanceof ECGenParameterSpec and - getECKeySize(cie.getArgument(0).(StringLiteral).getRepresentedString()) < 224 + getECKeySize(cie.getArgument(0).(StringLiteral).getRepresentedString()) < 256 ) and - msg = "Key size should be at least 224 bits for EC encryption." + msg = "Key size should be at least 256 bits for EC encryption." } from Expr e, string msg diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected index f350495d28f..421335b84ff 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.expected @@ -1,8 +1,11 @@ | InsufficientKeySize.java:9:9:9:24 | init(...) | Key size should be at least 128 bits for AES encryption. | | InsufficientKeySize.java:17:9:17:36 | initialize(...) | Key size should be at least 2048 bits for RSA encryption. | | InsufficientKeySize.java:25:9:25:36 | initialize(...) | Key size should be at least 2048 bits for DSA encryption. | -| InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | -| InsufficientKeySize.java:38:9:38:67 | initialize(...) | Key size should be at least 224 bits for EC encryption. | -| InsufficientKeySize.java:48:9:48:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | -| InsufficientKeySize.java:53:9:53:39 | initialize(...) | Key size should be at least 224 bits for EC encryption. | -| InsufficientKeySize.java:58:9:58:40 | initialize(...) | Key size should be at least 224 bits for EC encryption. | +| InsufficientKeySize.java:34:9:34:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:38:9:38:67 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:48:9:48:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:53:9:53:39 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:58:9:58:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:68:9:68:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:78:9:78:40 | initialize(...) | Key size should be at least 256 bits for EC encryption. | +| InsufficientKeySize.java:87:9:87:37 | initialize(...) | Key size should be at least 2048 bits for DH encryption. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java index 45b7c610df1..df46d6e69a9 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java @@ -29,37 +29,65 @@ public class InsufficientKeySize { keyPairGen4.initialize(2048); KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC"); - // BAD: Key size is less than 224 + // BAD: Key size is less than 256 ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1"); keyPairGen5.initialize(ecSpec1); KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC"); - // BAD: Key size is less than 224 + // BAD: Key size is less than 256 keyPairGen6.initialize(new ECGenParameterSpec("secp112r1")); KeyPairGenerator keyPairGen7 = KeyPairGenerator.getInstance("EC"); - // GOOD: Key size is no less than 224 + // GOOD: Key size is no less than 256 ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); keyPairGen7.initialize(ecSpec2); KeyPairGenerator keyPairGen8 = KeyPairGenerator.getInstance("EC"); - // BAD: Key size is less than 224 + // BAD: Key size is less than 256 ECGenParameterSpec ecSpec3 = new ECGenParameterSpec("X9.62 prime192v2"); keyPairGen8.initialize(ecSpec3); KeyPairGenerator keyPairGen9 = KeyPairGenerator.getInstance("EC"); - // BAD: Key size is less than 224 + // BAD: Key size is less than 256 ECGenParameterSpec ecSpec4 = new ECGenParameterSpec("X9.62 c2tnb191v3"); keyPairGen9.initialize(ecSpec4); KeyPairGenerator keyPairGen10 = KeyPairGenerator.getInstance("EC"); - // BAD: Key size is less than 224 + // BAD: Key size is less than 256 ECGenParameterSpec ecSpec5 = new ECGenParameterSpec("sect163k1"); keyPairGen10.initialize(ecSpec5); KeyPairGenerator keyPairGen11 = KeyPairGenerator.getInstance("EC"); - // GOOD: Key size is no less than 224 + // GOOD: Key size is no less than 256 ECGenParameterSpec ecSpec6 = new ECGenParameterSpec("X9.62 c2tnb359v1"); keyPairGen11.initialize(ecSpec6); + + KeyPairGenerator keyPairGen12 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 256 + ECGenParameterSpec ecSpec7 = new ECGenParameterSpec("prime192v2"); + keyPairGen12.initialize(ecSpec7); + + KeyPairGenerator keyPairGen13 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is no less than 256 + ECGenParameterSpec ecSpec8 = new ECGenParameterSpec("prime256v1"); + keyPairGen13.initialize(ecSpec8); + + KeyPairGenerator keyPairGen14 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is less than 256 + ECGenParameterSpec ecSpec9 = new ECGenParameterSpec("c2tnb191v1"); + keyPairGen14.initialize(ecSpec9); + + KeyPairGenerator keyPairGen15 = KeyPairGenerator.getInstance("EC"); + // BAD: Key size is no less than 256 + ECGenParameterSpec ecSpec10 = new ECGenParameterSpec("c2tnb431r1"); + keyPairGen15.initialize(ecSpec10); + + KeyPairGenerator keyPairGen16 = KeyPairGenerator.getInstance("dh"); + // BAD: Key size is less than 2048 + keyPairGen16.initialize(1024); + + KeyPairGenerator keyPairGen17 = KeyPairGenerator.getInstance("DH"); + // GOOD: Key size is no less than 2048 + keyPairGen17.initialize(2048); } } From 8880b38b1f65f601a9aadc8002dc9731bfe97763 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Thu, 28 Jan 2021 15:28:15 +0300 Subject: [PATCH 049/429] Rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref --- .../AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/{ => AccessOfMemoryLocationAfterEndOfBufferUsingStrlen}/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref (100%) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref similarity index 100% rename from cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref rename to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref From f65ec97ac210db005941e0292adee295296da837 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Thu, 28 Jan 2021 15:28:34 +0300 Subject: [PATCH 050/429] Rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c --- .../test.c | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/{ => AccessOfMemoryLocationAfterEndOfBufferUsingStrlen}/test.c (100%) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c similarity index 100% rename from cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c rename to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c From 8ed28157e118a44c29c2aade759f2a18a6e09727 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Thu, 28 Jan 2021 15:28:52 +0300 Subject: [PATCH 051/429] Rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected --- .../AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/{ => AccessOfMemoryLocationAfterEndOfBufferUsingStrlen}/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected (100%) diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected similarity index 100% rename from cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected rename to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected From c8eeb5f73e70c567dc062c7a3b143faa8063ec1a Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Fri, 29 Jan 2021 11:51:15 +0300 Subject: [PATCH 052/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.ql --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index e165d61985b..04a284d7846 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -22,6 +22,9 @@ class IfCompareWithZero extends IfStmt { or this.getCondition().(NEExpr).getAChild().getValue() = "0" and this.hasElse() + or + this.getCondition().(NEExpr).getAChild().getValue() = "0" and + this.getThen().getAChild*() instanceof ReturnStmt } } From bdbf5a4fae29511be7d64039847a1a70a7e61545 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Fri, 29 Jan 2021 13:41:45 +0300 Subject: [PATCH 053/429] Apply suggestions from code review Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp index 0232fc131eb..df69886e97b 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.cpp @@ -8,7 +8,9 @@ void badFunction(const int *source, std::size_t length) noexcept { void goodFunction(const int *source, std::size_t length) noexcept { try { int * dest = new int[length]; - } catch(std::bad_alloc) + } catch(std::bad_alloc) { + // ... + } std::memset(dest, 0, length); // .. } @@ -16,7 +18,9 @@ void goodFunction(const int *source, std::size_t length) noexcept { void badFunction(const int *source, std::size_t length) noexcept { try { int * dest = new (std::nothrow) int[length]; - } catch(std::bad_alloc) + } catch(std::bad_alloc) { + // ... + } std::memset(dest, 0, length); // .. } From 191962f64c6ac49134b388a755d5237cfc1f305e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 29 Jan 2021 12:01:38 +0100 Subject: [PATCH 054/429] C#: Add data flow 'getARuntimeTarget' predicate to 'FunctionPointerCall' --- .../internal/FunctionPointerDataFlow.qll | 205 ++++++++++++++++++ .../ql/src/semmle/code/csharp/exprs/Call.qll | 17 ++ .../functionpointers/FunctionPointerFlow.cs | 83 +++++++ .../FunctionPointerFlow.expected | 9 + .../functionpointers/FunctionPointerFlow.ql | 5 + 5 files changed, 319 insertions(+) create mode 100755 csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll create mode 100644 csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.cs create mode 100644 csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected create mode 100644 csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll new file mode 100755 index 00000000000..495beb93a22 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll @@ -0,0 +1,205 @@ +/** + * INTERNAL: Do not use. + * + * Provides classes for resolving function pointer calls. + */ + +import csharp +private import dotnet +private import semmle.code.csharp.dataflow.CallContext +private import semmle.code.csharp.dataflow.internal.DataFlowDispatch +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate +private import semmle.code.csharp.dataflow.internal.DataFlowPublic +private import semmle.code.csharp.dataflow.FlowSummary +private import semmle.code.csharp.dispatch.Dispatch +private import semmle.code.csharp.frameworks.system.linq.Expressions + +/** A source of flow for a function pointer expression. */ +private class FunctionPointerFlowSource extends DataFlow::ExprNode { + Callable c; + + FunctionPointerFlowSource() { + this.getExpr() = + any(Expr e | + c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration() + ) + } + + /** Gets the callable that is referenced in this function pointer flow source. */ + Callable getCallable() { result = c } +} + +/** A sink of flow for a function pointer expression. */ +abstract private class FunctionPointerFlowSink extends DataFlow::Node { + /** + * Gets an actual run-time target of this function pointer call in the given call + * context, if any. The call context records the *last* call required to + * resolve the target, if any. + * + * See examples in `DelegateFlowSink`. + */ + cached + Callable getARuntimeTarget(CallContext context) { + exists(FunctionPointerFlowSource fptrfs | + flowsFrom(this, fptrfs, _, context) and + result = fptrfs.getCallable() + ) + } +} + +/** A function pointer call expression. */ +class FunctionPointerCallExpr extends FunctionPointerFlowSink, DataFlow::ExprNode { + FunctionPointerCall fptrc; + + FunctionPointerCallExpr() { this.getExpr() = fptrc.getFunctionPointerExpr() } + + /** Gets the function pointer call that this expression belongs to. */ + FunctionPointerCall getFunctionPointerCall() { result = fptrc } +} + +/** A non-function pointer call. */ +private class NonFunctionPointerCall extends Expr { + private DispatchCall dc; + + NonFunctionPointerCall() { this = dc.getCall() } + + /** + * Gets a run-time target of this call. A target is always a source + * declaration, and if the callable has both CIL and source code, only + * the source code version is returned. + */ + Callable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) } + + /** Gets the `i`th argument of this call. */ + Expr getArgument(int i) { result = dc.getArgument(i) } +} + +private class NormalReturnNode extends Node { + NormalReturnNode() { this.(ReturnNode).getKind() instanceof NormalReturnKind } +} + +/** + * Holds if data can flow (inter-procedurally) to function pointer `sink` from + * `node`. This predicate searches backwards from `sink` to `node`. + * + * The parameter `isReturned` indicates whether the path from `sink` to + * `node` goes through a returned expression. The call context `lastCall` + * records the last call on the path from `node` to `sink`, if any. + */ +private predicate flowsFrom( + FunctionPointerFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall +) { + // Base case + sink = node and + isReturned = false and + lastCall instanceof EmptyCallContext + or + // Local flow + exists(DataFlow::Node mid | flowsFrom(sink, mid, isReturned, lastCall) | + LocalFlow::localFlowStepCommon(node, mid) + or + exists(Ssa::Definition def | + LocalFlow::localSsaFlowStep(def, node, mid) and + LocalFlow::usesInstanceField(def) + ) + ) + or + // Flow through static field or property + exists(DataFlow::Node mid | + flowsFrom(sink, mid, _, _) and + jumpStep(node, mid) and + isReturned = false and + lastCall instanceof EmptyCallContext + ) + or + // Flow into a callable (non-function pointer call) + exists(ParameterNode mid, CallContext prevLastCall, NonFunctionPointerCall call, Parameter p | + flowsFrom(sink, mid, isReturned, prevLastCall) and + isReturned = false and + p = mid.getParameter() and + flowIntoNonFunctionPointerCall(call, node.asExpr(), p) and + lastCall = getLastCall(prevLastCall, call, p.getPosition()) + ) + or + // Flow into a callable (function pointer call) + exists( + ParameterNode mid, CallContext prevLastCall, FunctionPointerCall call, Callable c, Parameter p, + int i + | + flowsFrom(sink, mid, isReturned, prevLastCall) and + isReturned = false and + flowIntoFunctionPointerCall(call, c, node.asExpr(), i) and + c.getParameter(i) = p and + p = mid.getParameter() and + lastCall = getLastCall(prevLastCall, call, i) + ) + or + // Flow out of a callable (non-function pointer call). + exists(DataFlow::ExprNode mid | + flowsFrom(sink, mid, _, lastCall) and + isReturned = true and + flowOutOfNonFunctionPointerCall(mid.getExpr(), node) + ) + or + // Flow out of a callable (function pointer call). + exists(DataFlow::ExprNode mid | + flowsFrom(sink, mid, _, _) and + isReturned = true and + flowOutOfFunctionPointerCall(mid.getExpr(), node, lastCall) + ) +} + +/** + * Gets the last call when tracking flow into `call`. The context + * `prevLastCall` is the previous last call, so the result is the + * previous call if it exists, otherwise `call` is the last call. + */ +bindingset[call, i] +private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) { + prevLastCall instanceof EmptyCallContext and + result.(ArgumentCallContext).isArgument(call, i) + or + prevLastCall instanceof ArgumentCallContext and + result = prevLastCall +} + +pragma[noinline] +private predicate flowIntoNonFunctionPointerCall( + NonFunctionPointerCall call, Expr arg, DotNet::Parameter p +) { + exists(DotNet::Callable callable, int i | + callable = call.getARuntimeTarget() and + p = callable.getAParameter() and + arg = call.getArgument(i) and + i = p.getPosition() + ) +} + +pragma[noinline] +private predicate flowIntoFunctionPointerCall(FunctionPointerCall call, Callable c, Expr arg, int i) { + exists(FunctionPointerFlowSource fptrfs, FunctionPointerCallExpr fptrce | + // the call context is irrelevant because the function pointer call + // itself will be the context + flowsFrom(fptrce, fptrfs, _, _) and + arg = call.getArgument(i) and + c = fptrfs.getCallable() and + call = fptrce.getFunctionPointerCall() + ) +} + +pragma[noinline] +private predicate flowOutOfNonFunctionPointerCall(NonFunctionPointerCall call, NormalReturnNode ret) { + call.getARuntimeTarget() = ret.getEnclosingCallable() +} + +pragma[noinline] +private predicate flowOutOfFunctionPointerCall( + FunctionPointerCall call, NormalReturnNode ret, CallContext lastCall +) { + exists(FunctionPointerFlowSource fptrfs, FunctionPointerCallExpr fptrce, Callable c | + flowsFrom(fptrce, fptrfs, _, lastCall) and + ret.getEnclosingCallable() = c and + c = fptrfs.getCallable() and + call = fptrce.getFunctionPointerCall() + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index a5348040d54..eb04d14d015 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -8,6 +8,7 @@ import Expr import semmle.code.csharp.Callable import semmle.code.csharp.dataflow.CallContext as CallContext private import semmle.code.csharp.dataflow.internal.DelegateDataFlow +private import semmle.code.csharp.dataflow.internal.FunctionPointerDataFlow private import semmle.code.csharp.dispatch.Dispatch private import dotnet @@ -618,8 +619,24 @@ class DelegateCall extends Call, @delegate_invocation_expr { class FunctionPointerCall extends Call, @function_pointer_invocation_expr { override Callable getTarget() { none() } + /** + * Gets a potential run-time target of this function pointer call in the given + * call context `cc`. + */ + Callable getARuntimeTarget(CallContext::CallContext cc) { + exists(FunctionPointerCallExpr call | + this = call.getFunctionPointerCall() and + result = call.getARuntimeTarget(cc) + ) + } + + override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } + override Expr getRuntimeArgument(int i) { result = getArgument(i) } + /** Gets the function pointer expression of this call. */ + Expr getFunctionPointerExpr() { result = this.getChild(-1) } + override string toString() { result = "function pointer call" } override string getAPrimaryQlClass() { result = "FunctionPointerCall" } diff --git a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.cs b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.cs new file mode 100644 index 00000000000..0ebbef4942d --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.cs @@ -0,0 +1,83 @@ +using System; + +unsafe class FunctionPointerFlow +{ + public static void Log1(int i) { } + public static void Log2(int i) { } + public static void Log3(int i) { } + public static void Log4(int i) { } + public static void Log5(int i) { } + public static void Log6(int i) { } + + public static void M2(delegate* a) + { + a(1); + a = &Log3; + a(2); + } + + public void M3() + { + M2(&Log1); + } + + public static void M4(delegate* a) + { + M2(a); + } + + public void M5() + { + M4(&Log2); + } + + public delegate* M6() + { + return &Log4; + } + + public void M7() + { + M6()(0); + } + + public void M8() + { + static void LocalFunction(int i) { }; + M2(&LocalFunction); + } + + private static delegate* field = &Log5; + + public void M9() + { + field(1); + } + + public void M10(delegate*, void> aa, delegate* a) + { + aa(a); + } + + public void M11() + { + M10(&M4, &Log6); + } + + public void M16(delegate*, void> aa, Action a) + { + aa(a); + } + + public static void M17(Action a) + { + a(0); + a = _ => { }; + a(0); + } + + public void M18() + { + M16(&M17, (i) => { }); + } +} diff --git a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected new file mode 100644 index 00000000000..ad2bfb887c0 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.expected @@ -0,0 +1,9 @@ +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:5:24:5:27 | Log1 | FunctionPointerFlow.cs:21:12:21:16 | &... | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:6:24:6:27 | Log2 | FunctionPointerFlow.cs:26:12:26:12 | access to parameter a | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:10:24:10:27 | Log6 | FunctionPointerFlow.cs:26:12:26:12 | access to parameter a | +| FunctionPointerFlow.cs:14:9:14:12 | function pointer call | FunctionPointerFlow.cs:46:9:46:44 | LocalFunction | FunctionPointerFlow.cs:47:12:47:25 | &... | +| FunctionPointerFlow.cs:16:9:16:12 | function pointer call | FunctionPointerFlow.cs:7:24:7:27 | Log3 | file://:0:0:0:0 | | +| FunctionPointerFlow.cs:41:9:41:15 | function pointer call | FunctionPointerFlow.cs:8:24:8:27 | Log4 | file://:0:0:0:0 | | +| FunctionPointerFlow.cs:54:9:54:16 | function pointer call | FunctionPointerFlow.cs:9:24:9:27 | Log5 | file://:0:0:0:0 | | +| FunctionPointerFlow.cs:59:9:59:13 | function pointer call | FunctionPointerFlow.cs:24:24:24:25 | M4 | FunctionPointerFlow.cs:64:13:64:15 | &... | +| FunctionPointerFlow.cs:69:9:69:13 | function pointer call | FunctionPointerFlow.cs:72:24:72:26 | M17 | FunctionPointerFlow.cs:81:13:81:16 | &... | diff --git a/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql new file mode 100644 index 00000000000..3434d068329 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/functionpointers/FunctionPointerFlow.ql @@ -0,0 +1,5 @@ +import csharp + +query predicate fptrCall(FunctionPointerCall fptrc, Callable c, CallContext::CallContext cc) { + c = fptrc.getARuntimeTarget(cc) +} From 91152d3a65dcdbc989602c57379bbb5462a95303 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 29 Jan 2021 12:02:11 +0100 Subject: [PATCH 055/429] Add additional tests to delegate call data flow --- .../dataflow/delegates/DelegateFlow.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs index 9479cca940d..68a91d02698 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs @@ -4,11 +4,11 @@ class DelegateFlow { void M1(int i) { } - void M2(Action a) + static void M2(Action a) { a(0); a = _ => { }; - a(0); + a(1); } void M3() @@ -108,4 +108,20 @@ class DelegateFlow } public delegate void MyDelegate(); + + public unsafe void M16(delegate*, void> fnptr, Action a) + { + fnptr(a); + } + + public unsafe void M17() + { + M16(&M2, (i) => {}); // MISSING: a(0) in M2 is calling this lambda + } + + public unsafe void M18() + { + delegate*, void> fnptr = &M2; + fnptr((i) => {}); // MISSING: a(0) in M2 is calling this lambda + } } From 76c9b6466e78481c7e6f0cc75ef1224b9a407c06 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Fri, 29 Jan 2021 11:27:30 +0000 Subject: [PATCH 056/429] Reformat TaintTrackingUtil.qll with more recent CodeQL CLI --- .../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index 35f820f9521..69189d949f1 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -686,8 +686,7 @@ private class FormatterCallable extends TaintPreservingCallable { ( this.hasName(["format", "out", "toString"]) or - this - .(Constructor) + this.(Constructor) .getParameterType(0) .(RefType) .getASourceSupertype*() From 92a5a2a06a7d3e7df4662182d5f23277830476a4 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 29 Jan 2021 13:34:19 +0100 Subject: [PATCH 057/429] C++: Solve merge conflicts by merging the two test.c test files. --- ...cationAfterEndOfBufferUsingStrlen.expected | 9 ++++ ...yLocationAfterEndOfBufferUsingStrlen.qlref | 0 ...cationAfterEndOfBufferUsingStrlen.expected | 9 ---- .../test.c | 44 ------------------ .../Security/CWE/CWE-788/semmle/tests/test.c | 45 +++++++++++++++++++ 5 files changed, 54 insertions(+), 53 deletions(-) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected rename cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/{AccessOfMemoryLocationAfterEndOfBufferUsingStrlen => }/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref (100%) delete mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected delete mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected new file mode 100644 index 00000000000..103afd8ffd9 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected @@ -0,0 +1,9 @@ +| test.c:42:3:42:24 | ... = ... | potential unsafe or redundant assignment. | +| test.c:43:3:43:40 | ... = ... | potential unsafe or redundant assignment. | +| test.c:44:3:44:40 | ... = ... | potential unsafe or redundant assignment. | +| test.c:45:3:45:44 | ... = ... | potential unsafe or redundant assignment. | +| test.c:46:3:46:44 | ... = ... | potential unsafe or redundant assignment. | +| test.c:47:3:47:48 | ... = ... | potential unsafe or redundant assignment. | +| test.c:48:3:48:48 | ... = ... | potential unsafe or redundant assignment. | +| test.c:49:3:49:50 | ... = ... | potential unsafe or redundant assignment. | +| test.c:50:3:50:50 | ... = ... | potential unsafe or redundant assignment. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref similarity index 100% rename from cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref rename to cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.qlref diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected deleted file mode 100644 index c2f02dd203e..00000000000 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.expected +++ /dev/null @@ -1,9 +0,0 @@ -| test.c:13:3:13:24 | ... = ... | potential unsafe or redundant assignment. | -| test.c:14:3:14:40 | ... = ... | potential unsafe or redundant assignment. | -| test.c:15:3:15:40 | ... = ... | potential unsafe or redundant assignment. | -| test.c:16:3:16:44 | ... = ... | potential unsafe or redundant assignment. | -| test.c:17:3:17:44 | ... = ... | potential unsafe or redundant assignment. | -| test.c:18:3:18:48 | ... = ... | potential unsafe or redundant assignment. | -| test.c:19:3:19:48 | ... = ... | potential unsafe or redundant assignment. | -| test.c:20:3:20:50 | ... = ... | potential unsafe or redundant assignment. | -| test.c:21:3:21:50 | ... = ... | potential unsafe or redundant assignment. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c deleted file mode 100644 index ce07a2ddba2..00000000000 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen/test.c +++ /dev/null @@ -1,44 +0,0 @@ -struct buffers -{ - unsigned char buff1[50]; - unsigned char *buff2; -} globalBuff1,*globalBuff2,globalBuff1_c,*globalBuff2_c; - - -void badFunc0(){ - unsigned char buff1[12]; - struct buffers buffAll; - struct buffers * buffAll1; - - buff1[strlen(buff1)]=0; // BAD - buffAll.buff1[strlen(buffAll.buff1)]=0; // BAD - buffAll.buff2[strlen(buffAll.buff2)]=0; // BAD - buffAll1->buff1[strlen(buffAll1->buff1)]=0; // BAD - buffAll1->buff2[strlen(buffAll1->buff2)]=0; // BAD - globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; // BAD - globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; // BAD - globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; // BAD - globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; // BAD -} -void noBadFunc0(){ - unsigned char buff1[12],buff1_c[12]; - struct buffers buffAll,buffAll_c; - struct buffers * buffAll1,*buffAll1_c; - - buff1[strlen(buff1_c)]=0; // GOOD - buffAll.buff1[strlen(buffAll_c.buff1)]=0; // GOOD - buffAll.buff2[strlen(buffAll.buff1)]=0; // GOOD - buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; // GOOD - buffAll1->buff2[strlen(buffAll1->buff1)]=0; // GOOD - globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; // GOOD - globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; // GOOD - globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; // GOOD - globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; // GOOD -} -void goodFunc0(){ - unsigned char buffer[12]; - int i; - for(i = 0; i < 6; i++) - buffer[i] = 'A'; - buffer[i]=0; -} diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c index c3347e1fd65..d986bb3b13c 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-788/semmle/tests/test.c @@ -26,3 +26,48 @@ void workFunction_2_1(char *s) { strncat(buf, s, len-strlen(buf)-1); // GOOD strncat(buf, s, len-strlen(buf)); // GOOD } + +struct buffers +{ + unsigned char buff1[50]; + unsigned char *buff2; +} globalBuff1,*globalBuff2,globalBuff1_c,*globalBuff2_c; + + +void badFunc0(){ + unsigned char buff1[12]; + struct buffers buffAll; + struct buffers * buffAll1; + + buff1[strlen(buff1)]=0; // BAD + buffAll.buff1[strlen(buffAll.buff1)]=0; // BAD + buffAll.buff2[strlen(buffAll.buff2)]=0; // BAD + buffAll1->buff1[strlen(buffAll1->buff1)]=0; // BAD + buffAll1->buff2[strlen(buffAll1->buff2)]=0; // BAD + globalBuff1.buff1[strlen(globalBuff1.buff1)]=0; // BAD + globalBuff1.buff2[strlen(globalBuff1.buff2)]=0; // BAD + globalBuff2->buff1[strlen(globalBuff2->buff1)]=0; // BAD + globalBuff2->buff2[strlen(globalBuff2->buff2)]=0; // BAD +} +void noBadFunc0(){ + unsigned char buff1[12],buff1_c[12]; + struct buffers buffAll,buffAll_c; + struct buffers * buffAll1,*buffAll1_c; + + buff1[strlen(buff1_c)]=0; // GOOD + buffAll.buff1[strlen(buffAll_c.buff1)]=0; // GOOD + buffAll.buff2[strlen(buffAll.buff1)]=0; // GOOD + buffAll1->buff1[strlen(buffAll1_c->buff1)]=0; // GOOD + buffAll1->buff2[strlen(buffAll1->buff1)]=0; // GOOD + globalBuff1.buff1[strlen(globalBuff1_c.buff1)]=0; // GOOD + globalBuff1.buff2[strlen(globalBuff1.buff1)]=0; // GOOD + globalBuff2->buff1[strlen(globalBuff2_c->buff1)]=0; // GOOD + globalBuff2->buff2[strlen(globalBuff2->buff1)]=0; // GOOD +} +void goodFunc0(){ + unsigned char buffer[12]; + int i; + for(i = 0; i < 6; i++) + buffer[i] = 'A'; + buffer[i]=0; +} From ff2f2b57925b0ce89efecfac6747cfee09898a1a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 Jan 2021 15:36:11 +0100 Subject: [PATCH 058/429] Python: Add django.shortcuts.redirect test --- .../library-tests/frameworks/django-v1/response_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py index f214cfb63d3..4ce50f98f81 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py @@ -1,4 +1,5 @@ from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, JsonResponse, HttpResponseNotFound +import django.shortcuts # Not an XSS sink, since the Content-Type is not "text/html" # FP reported in https://github.com/github/codeql-python-team/issues/38 @@ -48,6 +49,11 @@ def redirect_through_normal_response(request): return resp +def redirect_shortcut(request): + next = request.GET.get("next") + return django.shortcuts.redirect(next) # $ MISSING: HttpResponse HttpRedirectResponse redirectLocation=next + + # Ensure that simple subclasses are still vuln to XSS def xss__not_found(request): return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse mimetype=text/html responseBody=Attribute() From 9c01aa23045f869da6a1cf049e8fa1768a961fba Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 Jan 2021 15:41:00 +0100 Subject: [PATCH 059/429] Python: Add modeling for django.shortcuts.redirect --- .../src/semmle/python/frameworks/Django.qll | 86 ++++++++++++++++++- .../frameworks/django-v1/response_test.py | 2 +- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 4251b515322..375debe0a17 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -35,7 +35,7 @@ private module Django { * WARNING: Only holds for a few predefined attributes. */ private DataFlow::Node django_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in ["db", "urls", "http", "conf"] and + attr_name in ["db", "urls", "http", "conf", "shortcuts"] and ( t.start() and result = DataFlow::importNode("django" + "." + attr_name) @@ -1649,6 +1649,62 @@ private module Django { } } } + + // ------------------------------------------------------------------------- + // django.shortcuts + // ------------------------------------------------------------------------- + /** Gets a reference to the `django.shortcuts` module. */ + DataFlow::Node shortcuts() { result = django_attr("shortcuts") } + + /** Provides models for the `django.shortcuts` module */ + module shortcuts { + /** + * Gets a reference to the attribute `attr_name` of the `django.shortcuts` module. + * WARNING: Only holds for a few predefined attributes. + */ + private DataFlow::Node shortcuts_attr(DataFlow::TypeTracker t, string attr_name) { + attr_name in ["redirect"] and + ( + t.start() and + result = DataFlow::importNode("django.shortcuts" + "." + attr_name) + or + t.startInAttr(attr_name) and + result = shortcuts() + ) + or + // Due to bad performance when using normal setup with `shortcuts_attr(t2, attr_name).track(t2, t)` + // we have inlined that code and forced a join + exists(DataFlow::TypeTracker t2 | + exists(DataFlow::StepSummary summary | + shortcuts_attr_first_join(t2, attr_name, result, summary) and + t = t2.append(summary) + ) + ) + } + + pragma[nomagic] + private predicate shortcuts_attr_first_join( + DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, + DataFlow::StepSummary summary + ) { + DataFlow::StepSummary::step(shortcuts_attr(t2, attr_name), res, summary) + } + + /** + * Gets a reference to the attribute `attr_name` of the `django.shortcuts` module. + * WARNING: Only holds for a few predefined attributes. + */ + private DataFlow::Node shortcuts_attr(string attr_name) { + result = shortcuts_attr(DataFlow::TypeTracker::end(), attr_name) + } + + /** + * Gets a reference to the `django.shortcuts.redirect` function + * + * See https://docs.djangoproject.com/en/3.1/topics/http/shortcuts/#redirect + */ + DataFlow::Node redirect() { result = shortcuts_attr("redirect") } + } } // --------------------------------------------------------------------------- @@ -1956,4 +2012,32 @@ private module Django { ) } } + + // --------------------------------------------------------------------------- + // django.shortcuts.redirect + // --------------------------------------------------------------------------- + /** + * A call to `django.shortcuts.redirect`. + * + * Note: This works differently depending on what argument is used. + * _One_ option is to redirect to a full URL. + * + * See https://docs.djangoproject.com/en/3.1/topics/http/shortcuts/#redirect + */ + private class DjangoShortcutsRedirectCall extends HTTP::Server::HttpRedirectResponse::Range, + DataFlow::CfgNode { + override CallNode node; + + DjangoShortcutsRedirectCall() { node.getFunction() = django::shortcuts::redirect().asCfgNode() } + + override DataFlow::Node getRedirectLocation() { + result.asCfgNode() in [node.getArg(0), node.getArgByName("to")] + } + + override DataFlow::Node getBody() { none() } + + override DataFlow::Node getMimetypeOrContentTypeArg() { none() } + + override string getMimetypeDefault() { none() } + } } diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py index 4ce50f98f81..99dc97624aa 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py @@ -51,7 +51,7 @@ def redirect_through_normal_response(request): def redirect_shortcut(request): next = request.GET.get("next") - return django.shortcuts.redirect(next) # $ MISSING: HttpResponse HttpRedirectResponse redirectLocation=next + return django.shortcuts.redirect(next) # $ HttpResponse HttpRedirectResponse redirectLocation=next # Ensure that simple subclasses are still vuln to XSS From ef831bb16ff77e3a8a1b40f3792135f08f973d05 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 29 Jan 2021 16:21:39 +0100 Subject: [PATCH 060/429] Python: Fix tornado redirect QLdoc --- python/ql/src/semmle/python/frameworks/Tornado.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Tornado.qll b/python/ql/src/semmle/python/frameworks/Tornado.qll index 29c91654b4a..f9a537861a0 100644 --- a/python/ql/src/semmle/python/frameworks/Tornado.qll +++ b/python/ql/src/semmle/python/frameworks/Tornado.qll @@ -556,9 +556,9 @@ private module Tornado { // Response modeling // --------------------------------------------------------------------------- /** - * A call to `tornado.web.RequestHandler.write` method. + * A call to `tornado.web.RequestHandler.redirect` method. * - * See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.write + * See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.redirect */ private class TornadoRequestHandlerRedirectCall extends HTTP::Server::HttpRedirectResponse::Range, DataFlow::CfgNode { From 182d435dc600afa85ac95a5ca16bb7fb26c4bba7 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 18 Jan 2021 14:58:21 +0100 Subject: [PATCH 061/429] Python: Replace comprehension read-step by for read-step. Add a version targetting sequence nodes. --- .../dataflow/new/internal/DataFlowPrivate.qll | 126 +++++++++++++----- .../dataflow/coverage/dataflow.expected | 81 ++++++++++- .../experimental/dataflow/coverage/test.py | 20 ++- .../dataflow/regression/dataflow.expected | 2 + .../experimental/dataflow/regression/test.py | 4 +- 5 files changed, 188 insertions(+), 45 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index c4f236b0996..38478c6bc47 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -161,15 +161,6 @@ module EssaFlow { nodeFrom.(CfgNode).getNode() = nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue() or - // Definition - // `[a, b] = iterable` - // nodeFrom = `iterable`, cfg node - // nodeTo = `TIterableSequence([a, b])` - exists(UnpackingAssignmentDirectTarget target | - nodeFrom.asExpr() = target.getValue() and - nodeTo = TIterableSequenceNode(target) - ) - or // With definition // `with f(42) as x:` // nodeFrom is `f(42)`, cfg node @@ -1045,7 +1036,7 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) { or popReadStep(nodeFrom, c, nodeTo) or - comprehensionReadStep(nodeFrom, c, nodeTo) + forReadStep(nodeFrom, c, nodeTo) or attributeReadStep(nodeFrom, c, nodeTo) or @@ -1142,9 +1133,15 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { * also transfer other content, but only tuple content is further read from `sequence` into its elements. * * The strategy is then via several read-, store-, and flow steps: - * 1. [Flow] Content is transferred from `iterable` to `TIterableSequence(sequence)` via a + * 1. a) [Flow] Content is transferred from `iterable` to `TIterableSequence(sequence)` via a * flow step. From here, everything happens on the LHS. * + * b) [Read] If the unpacking happens inside a for as in + * ```python + * for sequence in iterable + * ``` + * then content is read from `iterable` to `TIterableSequence(sequence)`. + * * 2. [Flow] Content is transferred from `TIterableSequence(sequence)` to `sequence` via a * flow step. (Here only tuple content is relevant.) * @@ -1179,7 +1176,7 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { * Looking at the content propagation to `a`: * `["a", SOURCE]`: [ListElementContent] * - * --Step 1--> + * --Step 1a--> * * `TIterableSequence((a, b))`: [ListElementContent] * @@ -1205,7 +1202,7 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { * * `["a", [SOURCE]]`: [ListElementContent; ListElementContent] * - * --Step 1--> + * --Step 1a--> * * `TIterableSequence((a, [b, *c]))`: [ListElementContent; ListElementContent] * @@ -1238,13 +1235,53 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { * `c`: [ListElementContent] */ module UnpackingAssignment { + /** + * The target of a `for`, e.g. `x` in `for x in list` or in `[42 for x in list]`. + * This class also records the source, which in both above cases is `list`. + * This class abstracts away the differing representations of comprehensions and + * for statements. + */ + class ForTarget extends ControlFlowNode { + Expr source; + + ForTarget() { + exists(For for | + source = for.getIter() and + this.getNode() = for.getTarget() and + not for = any(Comp comp).getNthInnerLoop(0) + ) + or + exists(Comp comp | + source = comp.getIterable() and + this.getNode() = comp.getIterationVariable(0).getAStore() + ) + } + + Expr getSource() { result = source } + } + + /** The LHS of an assignemnt, it also records the assigned value. */ + class AssignmentTarget extends ControlFlowNode { + Expr value; + + AssignmentTarget() { + exists(Assign assign | this.getNode() = assign.getATarget() | value = assign.getValue()) + } + + Expr getValue() { result = value } + } + /** A direct (or top-level) target of an unpacking assignment. */ class UnpackingAssignmentDirectTarget extends ControlFlowNode { Expr value; UnpackingAssignmentDirectTarget() { this instanceof SequenceNode and - exists(Assign assign | this.getNode() = assign.getATarget() | value = assign.getValue()) + ( + value = this.(AssignmentTarget).getValue() + or + value = this.(ForTarget).getSource() + ) } Expr getValue() { result = value } @@ -1268,11 +1305,38 @@ module UnpackingAssignment { ControlFlowNode getAnElement() { result = this.getElement(_) } } + /** + * Step 1a + * Data flows from `iterable` to `TIterableSequence(sequence)` + */ + predicate unpackingAssignmentAssignmentFlowStep(Node nodeFrom, Node nodeTo) { + exists(AssignmentTarget target | + nodeFrom.asExpr() = target.getValue() and + nodeTo = TIterableSequenceNode(target) + ) + } + + /** + * Step 1b + * Data is read from `iterable` to `TIterableSequence(sequence)` + */ + predicate unpackingAssignmentForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { + exists(ForTarget target | + nodeFrom.asExpr() = target.getSource() and + nodeTo = TIterableSequenceNode(target.(SequenceNode)) + ) and + ( + c instanceof ListElementContent + or + c instanceof SetElementContent + ) + } + /** * Step 2 * Data flows from `TIterableSequence(sequence)` to `sequence` */ - predicate unpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) { + predicate unpackingAssignmentTupleFlowStep(Node nodeFrom, Node nodeTo) { exists(UnpackingAssignmentSequenceTarget target | nodeFrom = TIterableSequenceNode(target) and nodeTo.asCfgNode() = target @@ -1376,6 +1440,8 @@ module UnpackingAssignment { /** All read steps associated with unpacking assignment. */ predicate unpackingAssignmentReadStep(Node nodeFrom, Content c, Node nodeTo) { + unpackingAssignmentForReadStep(nodeFrom, c, nodeTo) + or unpackingAssignmentElementReadStep(nodeFrom, c, nodeTo) or unpackingAssignmentConvertingReadStep(nodeFrom, c, nodeTo) @@ -1387,6 +1453,13 @@ module UnpackingAssignment { or unpackingAssignmentConvertingStoreStep(nodeFrom, c, nodeTo) } + + /** All flow steps associated with unpacking assignment. */ + predicate unpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) { + unpackingAssignmentAssignmentFlowStep(nodeFrom, nodeTo) + or + unpackingAssignmentTupleFlowStep(nodeFrom, nodeTo) + } } import UnpackingAssignment @@ -1425,25 +1498,10 @@ predicate popReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { ) } -/** Data flows from a iterated sequence to the variable iterating over the sequence. */ -predicate comprehensionReadStep(CfgNode nodeFrom, Content c, EssaNode nodeTo) { - // Comprehension - // `[x+1 for x in l]` - // nodeFrom is `l`, cfg node - // nodeTo is `x`, essa var - // c denotes element of list or set - exists(Comp comp | - // outermost for - nodeFrom.getNode().getNode() = comp.getIterable() and - nodeTo.getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() = - comp.getIterationVariable(0).getAStore() - or - // an inner for - exists(int n | n > 0 | - nodeFrom.getNode().getNode() = comp.getNthInnerLoop(n).getIter() and - nodeTo.getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() = - comp.getNthInnerLoop(n).getTarget() - ) +predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { + exists(ForTarget target | + nodeFrom.asExpr() = target.getSource() and + nodeTo.asVar().(EssaNodeDefinition).getDefiningNode() = target ) and ( c instanceof ListElementContent diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index ef7ebb797cd..623b86e2a1d 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -285,7 +285,38 @@ edges | test.py:639:12:639:13 | ControlFlowNode for a2 [List element] | test.py:639:12:639:16 | ControlFlowNode for Subscript | | test.py:640:10:640:11 | ControlFlowNode for a2 [List element] | test.py:640:10:640:14 | ControlFlowNode for Subscript | | test.py:647:19:647:24 | ControlFlowNode for SOURCE | test.py:648:10:648:10 | ControlFlowNode for a | -| test.py:739:16:739:21 | ControlFlowNode for SOURCE | test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | +| test.py:655:10:655:51 | ControlFlowNode for List [List element, Tuple element at index 0] | test.py:656:16:656:17 | ControlFlowNode for tl [List element, Tuple element at index 0] | +| test.py:655:12:655:17 | ControlFlowNode for SOURCE | test.py:655:12:655:28 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:655:12:655:28 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:655:10:655:51 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:655:33:655:38 | ControlFlowNode for SOURCE | test.py:655:33:655:49 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:655:33:655:49 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:655:10:655:51 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:656:9:656:9 | SSA variable x | test.py:657:14:657:14 | ControlFlowNode for x | +| test.py:656:9:656:11 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:656:9:656:9 | SSA variable x | +| test.py:656:9:656:11 | IterableSequence [Tuple element at index 0] | test.py:656:9:656:11 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:656:16:656:17 | ControlFlowNode for tl [List element, Tuple element at index 0] | test.py:656:9:656:11 | IterableSequence [Tuple element at index 0] | +| test.py:663:10:663:51 | ControlFlowNode for List [List element, Tuple element at index 0] | test.py:664:17:664:18 | ControlFlowNode for tl [List element, Tuple element at index 0] | +| test.py:663:12:663:17 | ControlFlowNode for SOURCE | test.py:663:12:663:28 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:663:12:663:28 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:663:10:663:51 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:663:33:663:38 | ControlFlowNode for SOURCE | test.py:663:33:663:49 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:663:33:663:49 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:663:10:663:51 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:664:9:664:10 | IterableElement | test.py:664:9:664:10 | SSA variable x [List element] | +| test.py:664:9:664:10 | SSA variable x [List element] | test.py:666:14:666:14 | ControlFlowNode for x [List element] | +| test.py:664:9:664:12 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:664:9:664:10 | IterableElement | +| test.py:664:9:664:12 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:664:12:664:12 | SSA variable y | +| test.py:664:9:664:12 | IterableSequence [Tuple element at index 0] | test.py:664:9:664:12 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:664:12:664:12 | SSA variable y | test.py:667:16:667:16 | ControlFlowNode for y | +| test.py:664:17:664:18 | ControlFlowNode for tl [List element, Tuple element at index 0] | test.py:664:9:664:12 | IterableSequence [Tuple element at index 0] | +| test.py:666:14:666:14 | ControlFlowNode for x [List element] | test.py:666:14:666:17 | ControlFlowNode for Subscript | +| test.py:672:10:672:51 | ControlFlowNode for List [List element, Tuple element at index 0] | test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | +| test.py:672:12:672:17 | ControlFlowNode for SOURCE | test.py:672:12:672:28 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:672:12:672:28 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:672:10:672:51 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:672:33:672:38 | ControlFlowNode for SOURCE | test.py:672:33:672:49 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:672:33:672:49 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:672:10:672:51 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:673:9:673:9 | SSA variable x | test.py:674:14:674:14 | ControlFlowNode for x | +| test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:673:9:673:9 | SSA variable x | +| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | +| test.py:749:16:749:21 | ControlFlowNode for SOURCE | test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | nodes | datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() | | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | @@ -628,8 +659,42 @@ nodes | test.py:640:10:640:14 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | test.py:647:19:647:24 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:648:10:648:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | -| test.py:739:16:739:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() | +| test.py:655:10:655:51 | ControlFlowNode for List [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:655:12:655:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:655:12:655:28 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:655:33:655:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:655:33:655:49 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:656:9:656:9 | SSA variable x | semmle.label | SSA variable x | +| test.py:656:9:656:11 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:656:9:656:11 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] | +| test.py:656:16:656:17 | ControlFlowNode for tl [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for tl [List element, Tuple element at index 0] | +| test.py:657:14:657:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| test.py:663:10:663:51 | ControlFlowNode for List [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:663:12:663:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:663:12:663:28 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:663:33:663:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:663:33:663:49 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:664:9:664:10 | IterableElement | semmle.label | IterableElement | +| test.py:664:9:664:10 | SSA variable x [List element] | semmle.label | SSA variable x [List element] | +| test.py:664:9:664:12 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:664:9:664:12 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] | +| test.py:664:12:664:12 | SSA variable y | semmle.label | SSA variable y | +| test.py:664:17:664:18 | ControlFlowNode for tl [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for tl [List element, Tuple element at index 0] | +| test.py:666:14:666:14 | ControlFlowNode for x [List element] | semmle.label | ControlFlowNode for x [List element] | +| test.py:666:14:666:17 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:667:16:667:16 | ControlFlowNode for y | semmle.label | ControlFlowNode for y | +| test.py:672:10:672:51 | ControlFlowNode for List [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:672:12:672:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:672:12:672:28 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:672:33:672:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:672:33:672:49 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:673:9:673:9 | SSA variable x | semmle.label | SSA variable x | +| test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] | +| test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for tl [List element, Tuple element at index 0] | +| test.py:674:14:674:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | +| test.py:749:16:749:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() | #select | datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found | | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found | @@ -724,4 +789,12 @@ nodes | test.py:639:12:639:16 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:639:12:639:16 | ControlFlowNode for Subscript | Flow found | | test.py:640:10:640:14 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:640:10:640:14 | ControlFlowNode for Subscript | Flow found | | test.py:648:10:648:10 | ControlFlowNode for a | test.py:647:19:647:24 | ControlFlowNode for SOURCE | test.py:648:10:648:10 | ControlFlowNode for a | Flow found | -| test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | test.py:739:16:739:21 | ControlFlowNode for SOURCE | test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | Flow found | +| test.py:657:14:657:14 | ControlFlowNode for x | test.py:655:12:655:17 | ControlFlowNode for SOURCE | test.py:657:14:657:14 | ControlFlowNode for x | Flow found | +| test.py:657:14:657:14 | ControlFlowNode for x | test.py:655:33:655:38 | ControlFlowNode for SOURCE | test.py:657:14:657:14 | ControlFlowNode for x | Flow found | +| test.py:666:14:666:17 | ControlFlowNode for Subscript | test.py:663:12:663:17 | ControlFlowNode for SOURCE | test.py:666:14:666:17 | ControlFlowNode for Subscript | Flow found | +| test.py:666:14:666:17 | ControlFlowNode for Subscript | test.py:663:33:663:38 | ControlFlowNode for SOURCE | test.py:666:14:666:17 | ControlFlowNode for Subscript | Flow found | +| test.py:667:16:667:16 | ControlFlowNode for y | test.py:663:12:663:17 | ControlFlowNode for SOURCE | test.py:667:16:667:16 | ControlFlowNode for y | Flow found | +| test.py:667:16:667:16 | ControlFlowNode for y | test.py:663:33:663:38 | ControlFlowNode for SOURCE | test.py:667:16:667:16 | ControlFlowNode for y | Flow found | +| test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:12:672:17 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found | +| test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:33:672:38 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found | +| test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | test.py:749:16:749:21 | ControlFlowNode for SOURCE | test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 6a9854903e5..542ab161ed6 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -192,7 +192,7 @@ def test_nested_comprehension_deep_with_local_flow(): def test_nested_comprehension_dict(): d = {"s": [SOURCE]} x = [y for k, v in d.items() for y in v] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" + SINK(x[0]) #$ MISSING:flow="SOURCE, l:-2 -> x[0]" def test_nested_comprehension_paren(): @@ -203,12 +203,12 @@ def test_nested_comprehension_paren(): # Iterable unpacking in comprehensions def test_unpacking_comprehension(): x = [a for (a, b) in [(SOURCE, NONSOURCE)]] - SINK(x[0]) # Flow missing + SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" def test_star_unpacking_comprehension(): x = [a[0] for (*a, b) in [(SOURCE, NONSOURCE)]] - SINK(x[0]) # Flow missing + SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" # 6.2.8. Generator expressions @@ -654,7 +654,7 @@ def test_iterable_repacking(): def test_iterable_unpacking_in_for(): tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)] for x,y in tl: - SINK(x) #$ MISSING: flow="SOURCE, l:-2 -> x" + SINK(x) #$ flow="SOURCE, l:-2 -> x" SINK_F(y) @@ -663,8 +663,18 @@ def test_iterable_star_unpacking_in_for(): tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)] for *x,y in tl: SINK_F(x) - SINK(x[0]) #$ MISSING: flow="SOURCE, l:-3 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-3 -> x[0]" + SINK_F(y) #$ SPURIOUS: flow="SOURCE, l:-4 -> y" # FP here since we do not track the tuple lenght and so `*x` could be empty + + +@expects(6) +def test_iterable_star_unpacking_in_for_2(): + tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)] + for x,*y,z in tl: + SINK(x) #$ flow="SOURCE, l:-2 -> x" SINK_F(y) + SINK_F(y[0]) + SINK_F(z) def test_deep_callgraph(): diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.expected b/python/ql/test/experimental/dataflow/regression/dataflow.expected index 2fe69282e37..dfce2c72737 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.expected +++ b/python/ql/test/experimental/dataflow/regression/dataflow.expected @@ -21,3 +21,5 @@ | test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:186:14:186:14 | ControlFlowNode for t | | test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:197:14:197:14 | ControlFlowNode for t | | test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:199:14:199:14 | ControlFlowNode for t | +| test.py:202:10:202:15 | ControlFlowNode for SOURCE | test.py:204:14:204:14 | ControlFlowNode for i | +| test.py:202:10:202:15 | ControlFlowNode for SOURCE | test.py:205:10:205:10 | ControlFlowNode for i | diff --git a/python/ql/test/experimental/dataflow/regression/test.py b/python/ql/test/experimental/dataflow/regression/test.py index aa620b6ba5f..80c9c7e5e34 100644 --- a/python/ql/test/experimental/dataflow/regression/test.py +++ b/python/ql/test/experimental/dataflow/regression/test.py @@ -201,8 +201,8 @@ def flow_through_type_test_if_no_class(): def flow_in_iteration(): t = [SOURCE] for i in t: - SINK(i) # Flow not found - SINK(i) # Flow not found + SINK(i) + SINK(i) def flow_in_generator(): seq = [SOURCE] From 7f1affa122a1a2569533a97106674df37e3f82a3 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 29 Jan 2021 17:44:53 +0100 Subject: [PATCH 062/429] Python: UnpackingAssignment -> IterableUnpacking --- .../dataflow/new/internal/DataFlowPrivate.qll | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 38478c6bc47..694243e0e81 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -201,7 +201,7 @@ module EssaFlow { nodeFrom.asCfgNode() = nodeTo.asCfgNode().(IfExprNode).getAnOperand() or // Flow inside an unpacking assignment - unpackingAssignmentFlowStep(nodeFrom, nodeTo) + iterableUnpackingFlowStep(nodeFrom, nodeTo) or // Overflow keyword argument exists(CallNode call, CallableValue callable | @@ -898,7 +898,7 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) { or comprehensionStoreStep(nodeFrom, c, nodeTo) or - unpackingAssignmentStoreStep(nodeFrom, c, nodeTo) + iterableUnpackingStoreStep(nodeFrom, c, nodeTo) or attributeStoreStep(nodeFrom, c, nodeTo) or @@ -1032,7 +1032,7 @@ predicate kwOverflowStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node predicate readStep(Node nodeFrom, Content c, Node nodeTo) { subscriptReadStep(nodeFrom, c, nodeTo) or - unpackingAssignmentReadStep(nodeFrom, c, nodeTo) + iterableUnpackingReadStep(nodeFrom, c, nodeTo) or popReadStep(nodeFrom, c, nodeTo) or @@ -1234,7 +1234,7 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { * * `c`: [ListElementContent] */ -module UnpackingAssignment { +module IterableUnpacking { /** * The target of a `for`, e.g. `x` in `for x in list` or in `[42 for x in list]`. * This class also records the source, which in both above cases is `list`. @@ -1309,7 +1309,7 @@ module UnpackingAssignment { * Step 1a * Data flows from `iterable` to `TIterableSequence(sequence)` */ - predicate unpackingAssignmentAssignmentFlowStep(Node nodeFrom, Node nodeTo) { + predicate iterableUnpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) { exists(AssignmentTarget target | nodeFrom.asExpr() = target.getValue() and nodeTo = TIterableSequenceNode(target) @@ -1320,7 +1320,7 @@ module UnpackingAssignment { * Step 1b * Data is read from `iterable` to `TIterableSequence(sequence)` */ - predicate unpackingAssignmentForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { + predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { exists(ForTarget target | nodeFrom.asExpr() = target.getSource() and nodeTo = TIterableSequenceNode(target.(SequenceNode)) @@ -1336,7 +1336,7 @@ module UnpackingAssignment { * Step 2 * Data flows from `TIterableSequence(sequence)` to `sequence` */ - predicate unpackingAssignmentTupleFlowStep(Node nodeFrom, Node nodeTo) { + predicate iterableUnpackingTupleFlowStep(Node nodeFrom, Node nodeTo) { exists(UnpackingAssignmentSequenceTarget target | nodeFrom = TIterableSequenceNode(target) and nodeTo.asCfgNode() = target @@ -1349,7 +1349,7 @@ module UnpackingAssignment { * As `sequence` is modeled as a tuple, we will not read tuple content as that would allow * crosstalk. */ - predicate unpackingAssignmentConvertingReadStep(Node nodeFrom, Content c, Node nodeTo) { + predicate iterableUnpackingConvertingReadStep(Node nodeFrom, Content c, Node nodeTo) { exists(UnpackingAssignmentSequenceTarget target | nodeFrom = TIterableSequenceNode(target) and nodeTo = TIterableElementNode(target) and @@ -1368,7 +1368,7 @@ module UnpackingAssignment { * Content type is `TupleElementContent` with indices taken from the syntax. * For instance, if `sequence` is `(a, *b, c)`, content is written to index 0, 1, and 2. */ - predicate unpackingAssignmentConvertingStoreStep(Node nodeFrom, Content c, Node nodeTo) { + predicate iterableUnpackingConvertingStoreStep(Node nodeFrom, Content c, Node nodeTo) { exists(UnpackingAssignmentSequenceTarget target | nodeFrom = TIterableElementNode(target) and nodeTo.asCfgNode() = target and @@ -1388,7 +1388,7 @@ module UnpackingAssignment { * * c) If the element is a starred variable, with control-flow node `v`, `toNode` is `TIterableElement(v)`. */ - predicate unpackingAssignmentElementReadStep(Node nodeFrom, Content c, Node nodeTo) { + predicate iterableUnpackingElementReadStep(Node nodeFrom, Content c, Node nodeTo) { exists( UnpackingAssignmentSequenceTarget target, int index, ControlFlowNode element, int starIndex | @@ -1430,7 +1430,7 @@ module UnpackingAssignment { * Data flows from `TIterableElement(v)` to the essa variable for `v`, with * content type `ListElementContent`. */ - predicate unpackingAssignmentStarredElementStoreStep(Node nodeFrom, Content c, Node nodeTo) { + predicate iterableUnpackingStarredElementStoreStep(Node nodeFrom, Content c, Node nodeTo) { exists(ControlFlowNode starred | starred.getNode() instanceof Starred | nodeFrom = TIterableElementNode(starred) and nodeTo.asVar().getDefinition().(MultiAssignmentDefinition).getDefiningNode() = starred and @@ -1439,30 +1439,30 @@ module UnpackingAssignment { } /** All read steps associated with unpacking assignment. */ - predicate unpackingAssignmentReadStep(Node nodeFrom, Content c, Node nodeTo) { - unpackingAssignmentForReadStep(nodeFrom, c, nodeTo) + predicate iterableUnpackingReadStep(Node nodeFrom, Content c, Node nodeTo) { + iterableUnpackingForReadStep(nodeFrom, c, nodeTo) or - unpackingAssignmentElementReadStep(nodeFrom, c, nodeTo) + iterableUnpackingElementReadStep(nodeFrom, c, nodeTo) or - unpackingAssignmentConvertingReadStep(nodeFrom, c, nodeTo) + iterableUnpackingConvertingReadStep(nodeFrom, c, nodeTo) } /** All store steps associated with unpacking assignment. */ - predicate unpackingAssignmentStoreStep(Node nodeFrom, Content c, Node nodeTo) { - unpackingAssignmentStarredElementStoreStep(nodeFrom, c, nodeTo) + predicate iterableUnpackingStoreStep(Node nodeFrom, Content c, Node nodeTo) { + iterableUnpackingStarredElementStoreStep(nodeFrom, c, nodeTo) or - unpackingAssignmentConvertingStoreStep(nodeFrom, c, nodeTo) + iterableUnpackingConvertingStoreStep(nodeFrom, c, nodeTo) } /** All flow steps associated with unpacking assignment. */ - predicate unpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) { - unpackingAssignmentAssignmentFlowStep(nodeFrom, nodeTo) + predicate iterableUnpackingFlowStep(Node nodeFrom, Node nodeTo) { + iterableUnpackingAssignmentFlowStep(nodeFrom, nodeTo) or - unpackingAssignmentTupleFlowStep(nodeFrom, nodeTo) + iterableUnpackingTupleFlowStep(nodeFrom, nodeTo) } } -import UnpackingAssignment +import IterableUnpacking /** Data flows from a sequence to a call to `pop` on the sequence. */ predicate popReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) { From 05a138694d41323f8141784187e8bae028246ecb Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 29 Jan 2021 21:12:44 +0100 Subject: [PATCH 063/429] Python: Fix crashing test --- python/ql/test/experimental/dataflow/coverage/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 542ab161ed6..0da8b40b274 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -672,8 +672,7 @@ def test_iterable_star_unpacking_in_for_2(): tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)] for x,*y,z in tl: SINK(x) #$ flow="SOURCE, l:-2 -> x" - SINK_F(y) - SINK_F(y[0]) + SINK_F(y) # The list itself is not tainted (and is here empty) SINK_F(z) From b7df18b97e75879ffed2f2c430072c05eba43584 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Sun, 31 Jan 2021 15:16:40 +0300 Subject: [PATCH 064/429] Update AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql --- ...ssOfMemoryLocationAfterEndOfBufferUsingStrlen.ql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql index 3e1cfdd6396..012109074e9 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-788/AccessOfMemoryLocationAfterEndOfBufferUsingStrlen.ql @@ -13,11 +13,22 @@ import cpp import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.dataflow.DataFlow from StrlenCall fc, AssignExpr expr, ArrayExpr exprarr where exprarr = expr.getLValue() and expr.getRValue().getValue().toInt() = 0 and - exprarr.getArrayOffset() = fc and + globalValueNumber(exprarr.getArrayOffset()) = globalValueNumber(fc) and + not exists(Expr exptmp | + ( + DataFlow::localExprFlow(fc, exptmp) or + exptmp.getAChild*() = fc.getArgument(0).(VariableAccess).getTarget().getAnAccess() + ) and + dominates(exptmp, expr) and + postDominates(exptmp, fc) and + not exptmp.getEnclosingStmt() = fc.getEnclosingStmt() and + not exptmp.getEnclosingStmt() = expr.getEnclosingStmt() + ) and globalValueNumber(fc.getArgument(0)) = globalValueNumber(exprarr.getArrayBase()) select expr, "potential unsafe or redundant assignment." From 2b946aee5a3ff0c7d5e284e2ff7527e4dd79cda6 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Sun, 31 Jan 2021 15:21:54 +0300 Subject: [PATCH 065/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.ql --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index 04a284d7846..403d8388b17 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -58,7 +58,7 @@ class WrongCheckErrorOperatorNew extends FunctionCall { predicate isExistsIfCondition() { exists(IfCompareWithZero ifc, AssignExpr aex, Initializer it | // call `operator new` directly from the condition of `operator if`. - this = ifc.getCondition().getAChild() + this = ifc.getCondition().getAChild*() or // check results call `operator new` with variable appropriation postDominates(ifc, this) and From 27fd46b8558cfd825baed747a90073aeb9f63ad1 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 1 Feb 2021 08:55:20 +0100 Subject: [PATCH 066/429] Python: Update test expectation --- .../test/experimental/dataflow/coverage/dataflow.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index 623b86e2a1d..978b810ea23 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -316,7 +316,7 @@ edges | test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:673:9:673:9 | SSA variable x | | test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | test.py:673:9:673:14 | ControlFlowNode for Tuple [Tuple element at index 0] | | test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | -| test.py:749:16:749:21 | ControlFlowNode for SOURCE | test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | +| test.py:748:16:748:21 | ControlFlowNode for SOURCE | test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | nodes | datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() | | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | @@ -693,8 +693,8 @@ nodes | test.py:673:9:673:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] | | test.py:673:19:673:20 | ControlFlowNode for tl [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for tl [List element, Tuple element at index 0] | | test.py:674:14:674:14 | ControlFlowNode for x | semmle.label | ControlFlowNode for x | -| test.py:749:16:749:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | -| test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() | +| test.py:748:16:748:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() | #select | datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found | | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found | @@ -797,4 +797,4 @@ nodes | test.py:667:16:667:16 | ControlFlowNode for y | test.py:663:33:663:38 | ControlFlowNode for SOURCE | test.py:667:16:667:16 | ControlFlowNode for y | Flow found | | test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:12:672:17 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found | | test.py:674:14:674:14 | ControlFlowNode for x | test.py:672:33:672:38 | ControlFlowNode for SOURCE | test.py:674:14:674:14 | ControlFlowNode for x | Flow found | -| test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | test.py:749:16:749:21 | ControlFlowNode for SOURCE | test.py:752:10:752:36 | ControlFlowNode for return_from_inner_scope() | Flow found | +| test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | test.py:748:16:748:21 | ControlFlowNode for SOURCE | test.py:751:10:751:36 | ControlFlowNode for return_from_inner_scope() | Flow found | From 2a9e66a6675409f60164f32e73f17e187bfa1f76 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 1 Feb 2021 11:17:04 +0100 Subject: [PATCH 067/429] Python: Fix problem after merge conflict --- python/ql/src/semmle/python/frameworks/Tornado.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/ql/src/semmle/python/frameworks/Tornado.qll b/python/ql/src/semmle/python/frameworks/Tornado.qll index 195bddf1552..1f5859c4945 100644 --- a/python/ql/src/semmle/python/frameworks/Tornado.qll +++ b/python/ql/src/semmle/python/frameworks/Tornado.qll @@ -586,6 +586,8 @@ private module Tornado { override DataFlow::Node getBody() { none() } override string getMimetypeDefault() { none() } + + override DataFlow::Node getMimetypeOrContentTypeArg() { none() } } /** From 3363f5e6dbbba32dada345a76238b73fc3e24732 Mon Sep 17 00:00:00 2001 From: CaptainFreak Date: Mon, 1 Feb 2021 18:01:34 +0530 Subject: [PATCH 068/429] JS: add query for Express-HBS LFR --- .../Security/CWE-073/ExpressHbsLFR.ql | 44 +++++++++++++++++++ .../documentation-examples/ExpressHbsLFR.js | 10 +++++ .../ExpressHbsLFR_fixed.js | 10 +++++ 3 files changed, 64 insertions(+) create mode 100644 javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql create mode 100644 javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js create mode 100644 javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js diff --git a/javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql b/javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql new file mode 100644 index 00000000000..de66932a7af --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql @@ -0,0 +1,44 @@ +/** + * @name Express-Hbs Local File Read and Potential RCE + * @description Writing user input directly to res.render of ExpressJS used with Hbs can lead to LFR + * @kind path-problem + * @problem.severity error + * @precision high + * @id js/express-hbs-lfr + * @tags security + * external/cwe/cwe-073 + * external/cwe/cwe-094 + */ + +import javascript +import DataFlow +import PathGraph +import Express +import semmle.javascript.DynamicPropertyAccess + +predicate isUsingHbsEngine() { + exists(MethodCallExpr method | + method.getMethodName() = "set" and + Express::appCreation().flowsToExpr(method.getReceiver()) and + method.getArgument(1).getStringValue().matches("hbs") + ) +} + +class HbsLFRTaint extends TaintTracking::Configuration { + HbsLFRTaint() { this = "HbsLFRTaint" } + + override predicate isSource(Node node) { node instanceof RemoteFlowSource } + + override predicate isSink(Node node) { + exists(MethodCallExpr mc | + Express::isResponse(mc.getReceiver()) and + mc.getMethodName() = "render" and + node.asExpr() = mc.getArgument(1) and + isUsingHbsEngine() + ) + } +} + +from HbsLFRTaint cfg, Node source, Node sink +where cfg.hasFlow(source, sink) +select source, sink diff --git a/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js b/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js new file mode 100644 index 00000000000..3e0e42f33ca --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js @@ -0,0 +1,10 @@ +var app = require('express')(); +app.set('view engine', 'hbs'); + +app.post('/path', function(req, res) { + var bodyParameter = req.body.bodyParameter + var queryParameter = req.query.queryParameter + + res.render('template', bodyParameter) + res.render('template', queryParameter) +}); \ No newline at end of file diff --git a/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js b/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js new file mode 100644 index 00000000000..54e8e865a1d --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js @@ -0,0 +1,10 @@ +var app = require('express')(); +app.set('view engine', 'hbs'); + +app.post('/path', function(req, res) { + var bodyParameter = req.body.bodyParameter + var queryParameter = req.query.queryParameter + + res.render('template', {bodyParameter}) + res.render('template', {queryParameter}) +}); \ No newline at end of file From 7d62e33feb871d005dfb938056e1d1bce6af0ff7 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 1 Feb 2021 11:38:52 +0100 Subject: [PATCH 069/429] C#: Rework function pointer/delegate call DF --- csharp/ql/src/Dead Code/DeadStoreOfLocal.ql | 2 +- .../raw/internal/desugar/Delegate.qll | 4 +- .../code/csharp/dataflow/CallContext.qll | 25 ++- .../dataflow/internal/DelegateDataFlow.qll | 76 +++++-- .../internal/FunctionPointerDataFlow.qll | 205 ------------------ .../code/csharp/dataflow/internal/SsaImpl.qll | 2 +- .../ql/src/semmle/code/csharp/exprs/Call.qll | 78 ++++--- .../semmle/code/csharp/metrics/Coupling.qll | 2 +- .../dataflow/delegates/DelegateFlow.cs | 4 +- .../dataflow/delegates/DelegateFlow.expected | 2 + .../expressions/DelegateCall1.ql | 2 +- .../expressions/DelegateCall2.ql | 2 +- .../expressions/DelegateCall3.ql | 2 +- .../library-tests/expressions/EventAccess3.ql | 2 +- 14 files changed, 133 insertions(+), 275 deletions(-) delete mode 100755 csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll diff --git a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql index 2e8d1b92e02..4e214c6f6d0 100644 --- a/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql +++ b/csharp/ql/src/Dead Code/DeadStoreOfLocal.ql @@ -63,7 +63,7 @@ predicate mayEscape(LocalVariable v) { exists(Callable c, Expr e, Expr succ | c = getACapturingCallableAncestor(v) | e = getADelegateExpr(c) and DataFlow::localExprFlow(e, succ) and - not succ = any(DelegateCall dc).getDelegateExpr() and + not succ = any(DelegateCall dc).getExpr() and not succ = any(Cast cast).getExpr() and not succ = any(Call call | nonEscapingCall(call)).getAnArgument() and not succ = any(AssignableDefinition ad | ad.getTarget() instanceof LocalVariable).getSource() diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll index 939f14ba8fe..f7c80e497fa 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Delegate.qll @@ -97,9 +97,7 @@ private class TranslatedDelegateInvokeCall extends TranslatedCompilerGeneratedCa ) } - override TranslatedExprBase getQualifier() { - result = getTranslatedExpr(generatedBy.getDelegateExpr()) - } + override TranslatedExprBase getQualifier() { result = getTranslatedExpr(generatedBy.getExpr()) } override Instruction getQualifierResult() { result = getQualifier().getResult() } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll index b0a6d9d98ed..aa501a58e0d 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll @@ -11,7 +11,8 @@ cached private newtype TCallContext = TEmptyCallContext() or TArgNonDelegateCallContext(Expr arg) { exists(DispatchCall dc | arg = dc.getArgument(_)) } or - TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } + TArgDelegateCallContext(DelegateCall dc, int i) { exists(dc.getArgument(i)) } or + TArgFunctionPointerCallContext(FunctionPointerCall fptrc, int i) { exists(fptrc.getArgument(i)) } /** * A call context. @@ -60,12 +61,14 @@ class NonDelegateCallArgumentCallContext extends ArgumentCallContext, TArgNonDel override Location getLocation() { result = arg.getLocation() } } -/** An argument of a delegate call. */ -class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateCallContext { - DelegateCall dc; +/** An argument of a delegate or function pointer call. */ +class DelegateLikeCallArgumentCallContext extends ArgumentCallContext { + DelegateLikeCall dc; int arg; - DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) } + DelegateLikeCallArgumentCallContext() { + this = TArgDelegateCallContext(dc, arg) or this = TArgFunctionPointerCallContext(dc, arg) + } override predicate isArgument(Expr call, int i) { call = dc and @@ -76,3 +79,15 @@ class DelegateCallArgumentCallContext extends ArgumentCallContext, TArgDelegateC override Location getLocation() { result = dc.getArgument(arg).getLocation() } } + +/** An argument of a delegate call. */ +class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, + TArgDelegateCallContext { + DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) } +} + +/** An argument of a function pointer call. */ +class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, + TArgFunctionPointerCallContext { + FunctionPointerCallArgumentCallContext() { this = TArgFunctionPointerCallContext(dc, arg) } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index 0001dd357b0..af70cb19654 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -14,8 +14,14 @@ private import semmle.code.csharp.dataflow.FlowSummary private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.system.linq.Expressions +/** A source of flow for a delegate or function pointer expression. */ +private class DelegateLikeFlowSource extends DataFlow::ExprNode { + /** Gets the callable that is referenced in this delegate or function pointer flow source. */ + Callable getCallable() { none() } +} + /** A source of flow for a delegate expression. */ -private class DelegateFlowSource extends DataFlow::ExprNode { +private class DelegateFlowSource extends DelegateLikeFlowSource { Callable c; DelegateFlowSource() { @@ -27,11 +33,26 @@ private class DelegateFlowSource extends DataFlow::ExprNode { } /** Gets the callable that is referenced in this delegate flow source. */ - Callable getCallable() { result = c } + override Callable getCallable() { result = c } } -/** A sink of flow for a delegate expression. */ -abstract private class DelegateFlowSink extends DataFlow::Node { +/** A source of flow for a function pointer expression. */ +private class FunctionPointerFlowSource extends DelegateLikeFlowSource { + Callable c; + + FunctionPointerFlowSource() { + this.getExpr() = + any(Expr e | + c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration() + ) + } + + /** Gets the callable that is referenced in this function pointer flow source. */ + override Callable getCallable() { result = c } +} + +/** A sink of flow for a delegate or function pointer expression. */ +abstract private class DelegateLikeFlowSink extends DataFlow::Node { /** * Gets an actual run-time target of this delegate call in the given call * context, if any. The call context records the *last* call required to @@ -85,25 +106,41 @@ abstract private class DelegateFlowSink extends DataFlow::Node { */ cached Callable getARuntimeTarget(CallContext context) { - exists(DelegateFlowSource dfs | + exists(DelegateLikeFlowSource dfs | flowsFrom(this, dfs, _, context) and result = dfs.getCallable() ) } } +/** A delegate or function pointer call expression. */ +class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode { + /** Gets the delegate or function pointer call that this expression belongs to. */ + DelegateLikeCall getCall() { none() } +} + /** A delegate call expression. */ -class DelegateCallExpr extends DelegateFlowSink, DataFlow::ExprNode { +class DelegateCallExpr extends DelegateLikeCallExpr { DelegateCall dc; - DelegateCallExpr() { this.getExpr() = dc.getDelegateExpr() } + DelegateCallExpr() { this.getExpr() = dc.getExpr() } /** Gets the delegate call that this expression belongs to. */ - DelegateCall getDelegateCall() { result = dc } + override DelegateCall getCall() { result = dc } +} + +/** A function pointer call expression. */ +class FunctionPointerCallExpr extends DelegateLikeCallExpr { + FunctionPointerCall fptrc; + + FunctionPointerCallExpr() { this.getExpr() = fptrc.getExpr() } + + /** Gets the function pointer call that this expression belongs to. */ + override FunctionPointerCall getCall() { result = fptrc } } /** A parameter of delegate type belonging to a callable with a flow summary. */ -class SummaryDelegateParameterSink extends DelegateFlowSink, ParameterNode { +class SummaryDelegateParameterSink extends DelegateLikeFlowSink, ParameterNode { SummaryDelegateParameterSink() { this.getType() instanceof SystemLinqExpressions::DelegateExtType and this.isParameterOf(any(SummarizedCallable c), _) @@ -111,7 +148,7 @@ class SummaryDelegateParameterSink extends DelegateFlowSink, ParameterNode { } /** A delegate expression that is added to an event. */ -class AddEventSource extends DelegateFlowSink, DataFlow::ExprNode { +class AddEventSource extends DelegateLikeFlowSink, DataFlow::ExprNode { AddEventExpr ae; AddEventSource() { this.getExpr() = ae.getRValue() } @@ -150,7 +187,7 @@ private class NormalReturnNode extends Node { * records the last call on the path from `node` to `sink`, if any. */ private predicate flowsFrom( - DelegateFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall + DelegateLikeFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall ) { // Base case sink = node and @@ -188,7 +225,8 @@ private predicate flowsFrom( or // Flow into a callable (delegate call) exists( - ParameterNode mid, CallContext prevLastCall, DelegateCall call, Callable c, Parameter p, int i + ParameterNode mid, CallContext prevLastCall, DelegateLikeCall call, Callable c, Parameter p, + int i | flowsFrom(sink, mid, isReturned, prevLastCall) and isReturned = false and @@ -238,14 +276,14 @@ private predicate flowIntoNonDelegateCall(NonDelegateCall call, Expr arg, DotNet } pragma[noinline] -private predicate flowIntoDelegateCall(DelegateCall call, Callable c, Expr arg, int i) { - exists(DelegateFlowSource dfs, DelegateCallExpr dce | +private predicate flowIntoDelegateCall(DelegateLikeCall call, Callable c, Expr arg, int i) { + exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce | // the call context is irrelevant because the delegate call // itself will be the context flowsFrom(dce, dfs, _, _) and arg = call.getArgument(i) and c = dfs.getCallable() and - call = dce.getDelegateCall() + call = dce.getCall() ) } @@ -255,11 +293,13 @@ private predicate flowOutOfNonDelegateCall(NonDelegateCall call, NormalReturnNod } pragma[noinline] -private predicate flowOutOfDelegateCall(DelegateCall dc, NormalReturnNode ret, CallContext lastCall) { - exists(DelegateFlowSource dfs, DelegateCallExpr dce, Callable c | +private predicate flowOutOfDelegateCall( + DelegateLikeCall dc, NormalReturnNode ret, CallContext lastCall +) { + exists(DelegateLikeFlowSource dfs, DelegateLikeCallExpr dce, Callable c | flowsFrom(dce, dfs, _, lastCall) and ret.getEnclosingCallable() = c and c = dfs.getCallable() and - dc = dce.getDelegateCall() + dc = dce.getCall() ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll deleted file mode 100755 index 495beb93a22..00000000000 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/FunctionPointerDataFlow.qll +++ /dev/null @@ -1,205 +0,0 @@ -/** - * INTERNAL: Do not use. - * - * Provides classes for resolving function pointer calls. - */ - -import csharp -private import dotnet -private import semmle.code.csharp.dataflow.CallContext -private import semmle.code.csharp.dataflow.internal.DataFlowDispatch -private import semmle.code.csharp.dataflow.internal.DataFlowPrivate -private import semmle.code.csharp.dataflow.internal.DataFlowPublic -private import semmle.code.csharp.dataflow.FlowSummary -private import semmle.code.csharp.dispatch.Dispatch -private import semmle.code.csharp.frameworks.system.linq.Expressions - -/** A source of flow for a function pointer expression. */ -private class FunctionPointerFlowSource extends DataFlow::ExprNode { - Callable c; - - FunctionPointerFlowSource() { - this.getExpr() = - any(Expr e | - c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration() - ) - } - - /** Gets the callable that is referenced in this function pointer flow source. */ - Callable getCallable() { result = c } -} - -/** A sink of flow for a function pointer expression. */ -abstract private class FunctionPointerFlowSink extends DataFlow::Node { - /** - * Gets an actual run-time target of this function pointer call in the given call - * context, if any. The call context records the *last* call required to - * resolve the target, if any. - * - * See examples in `DelegateFlowSink`. - */ - cached - Callable getARuntimeTarget(CallContext context) { - exists(FunctionPointerFlowSource fptrfs | - flowsFrom(this, fptrfs, _, context) and - result = fptrfs.getCallable() - ) - } -} - -/** A function pointer call expression. */ -class FunctionPointerCallExpr extends FunctionPointerFlowSink, DataFlow::ExprNode { - FunctionPointerCall fptrc; - - FunctionPointerCallExpr() { this.getExpr() = fptrc.getFunctionPointerExpr() } - - /** Gets the function pointer call that this expression belongs to. */ - FunctionPointerCall getFunctionPointerCall() { result = fptrc } -} - -/** A non-function pointer call. */ -private class NonFunctionPointerCall extends Expr { - private DispatchCall dc; - - NonFunctionPointerCall() { this = dc.getCall() } - - /** - * Gets a run-time target of this call. A target is always a source - * declaration, and if the callable has both CIL and source code, only - * the source code version is returned. - */ - Callable getARuntimeTarget() { result = getCallableForDataFlow(dc.getADynamicTarget()) } - - /** Gets the `i`th argument of this call. */ - Expr getArgument(int i) { result = dc.getArgument(i) } -} - -private class NormalReturnNode extends Node { - NormalReturnNode() { this.(ReturnNode).getKind() instanceof NormalReturnKind } -} - -/** - * Holds if data can flow (inter-procedurally) to function pointer `sink` from - * `node`. This predicate searches backwards from `sink` to `node`. - * - * The parameter `isReturned` indicates whether the path from `sink` to - * `node` goes through a returned expression. The call context `lastCall` - * records the last call on the path from `node` to `sink`, if any. - */ -private predicate flowsFrom( - FunctionPointerFlowSink sink, DataFlow::Node node, boolean isReturned, CallContext lastCall -) { - // Base case - sink = node and - isReturned = false and - lastCall instanceof EmptyCallContext - or - // Local flow - exists(DataFlow::Node mid | flowsFrom(sink, mid, isReturned, lastCall) | - LocalFlow::localFlowStepCommon(node, mid) - or - exists(Ssa::Definition def | - LocalFlow::localSsaFlowStep(def, node, mid) and - LocalFlow::usesInstanceField(def) - ) - ) - or - // Flow through static field or property - exists(DataFlow::Node mid | - flowsFrom(sink, mid, _, _) and - jumpStep(node, mid) and - isReturned = false and - lastCall instanceof EmptyCallContext - ) - or - // Flow into a callable (non-function pointer call) - exists(ParameterNode mid, CallContext prevLastCall, NonFunctionPointerCall call, Parameter p | - flowsFrom(sink, mid, isReturned, prevLastCall) and - isReturned = false and - p = mid.getParameter() and - flowIntoNonFunctionPointerCall(call, node.asExpr(), p) and - lastCall = getLastCall(prevLastCall, call, p.getPosition()) - ) - or - // Flow into a callable (function pointer call) - exists( - ParameterNode mid, CallContext prevLastCall, FunctionPointerCall call, Callable c, Parameter p, - int i - | - flowsFrom(sink, mid, isReturned, prevLastCall) and - isReturned = false and - flowIntoFunctionPointerCall(call, c, node.asExpr(), i) and - c.getParameter(i) = p and - p = mid.getParameter() and - lastCall = getLastCall(prevLastCall, call, i) - ) - or - // Flow out of a callable (non-function pointer call). - exists(DataFlow::ExprNode mid | - flowsFrom(sink, mid, _, lastCall) and - isReturned = true and - flowOutOfNonFunctionPointerCall(mid.getExpr(), node) - ) - or - // Flow out of a callable (function pointer call). - exists(DataFlow::ExprNode mid | - flowsFrom(sink, mid, _, _) and - isReturned = true and - flowOutOfFunctionPointerCall(mid.getExpr(), node, lastCall) - ) -} - -/** - * Gets the last call when tracking flow into `call`. The context - * `prevLastCall` is the previous last call, so the result is the - * previous call if it exists, otherwise `call` is the last call. - */ -bindingset[call, i] -private CallContext getLastCall(CallContext prevLastCall, Expr call, int i) { - prevLastCall instanceof EmptyCallContext and - result.(ArgumentCallContext).isArgument(call, i) - or - prevLastCall instanceof ArgumentCallContext and - result = prevLastCall -} - -pragma[noinline] -private predicate flowIntoNonFunctionPointerCall( - NonFunctionPointerCall call, Expr arg, DotNet::Parameter p -) { - exists(DotNet::Callable callable, int i | - callable = call.getARuntimeTarget() and - p = callable.getAParameter() and - arg = call.getArgument(i) and - i = p.getPosition() - ) -} - -pragma[noinline] -private predicate flowIntoFunctionPointerCall(FunctionPointerCall call, Callable c, Expr arg, int i) { - exists(FunctionPointerFlowSource fptrfs, FunctionPointerCallExpr fptrce | - // the call context is irrelevant because the function pointer call - // itself will be the context - flowsFrom(fptrce, fptrfs, _, _) and - arg = call.getArgument(i) and - c = fptrfs.getCallable() and - call = fptrce.getFunctionPointerCall() - ) -} - -pragma[noinline] -private predicate flowOutOfNonFunctionPointerCall(NonFunctionPointerCall call, NormalReturnNode ret) { - call.getARuntimeTarget() = ret.getEnclosingCallable() -} - -pragma[noinline] -private predicate flowOutOfFunctionPointerCall( - FunctionPointerCall call, NormalReturnNode ret, CallContext lastCall -) { - exists(FunctionPointerFlowSource fptrfs, FunctionPointerCallExpr fptrce, Callable c | - flowsFrom(fptrce, fptrfs, _, lastCall) and - ret.getEnclosingCallable() = c and - c = fptrfs.getCallable() and - call = fptrce.getFunctionPointerCall() - ) -} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll index 3014e33a63b..b29f12e279b 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -245,7 +245,7 @@ private module CallGraph { * a library callable and `e` is a delegate argument. */ private predicate delegateCall(Call c, Expr e, boolean libraryDelegateCall) { - c = any(DelegateCall dc | e = dc.getDelegateExpr()) and + c = any(DelegateCall dc | e = dc.getExpr()) and libraryDelegateCall = false or c.getTarget().fromLibrary() and diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index eb04d14d015..941873d9afd 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -8,7 +8,6 @@ import Expr import semmle.code.csharp.Callable import semmle.code.csharp.dataflow.CallContext as CallContext private import semmle.code.csharp.dataflow.internal.DelegateDataFlow -private import semmle.code.csharp.dataflow.internal.FunctionPointerDataFlow private import semmle.code.csharp.dispatch.Dispatch private import dotnet @@ -528,6 +527,39 @@ class MutatorOperatorCall extends OperatorCall { predicate isPostfix() { mutator_invocation_mode(this, 2) } } +/** + * A function pointer or delegate call. + */ +abstract class DelegateLikeCall extends Call { + override Callable getTarget() { none() } + + /** + * Gets a potential run-time target of this delegate or function pointer call in the given + * call context `cc`. + */ + Callable getARuntimeTarget(CallContext::CallContext cc) { none() } + + /** + * Gets the delegate or function pointer expression of this call. For example, the + * delegate expression of `X()` on line 5 is the access to the field `X` in + * + * ```csharp + * class A { + * Action X = () => { }; + * + * void CallX() { + * X(); + * } + * } + * ``` + */ + Expr getExpr() { result = this.getChild(-1) } + + override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } + + override Expr getRuntimeArgument(int i) { result = getArgument(i) } +} + /** * A delegate call, for example `x()` on line 5 in * @@ -541,16 +573,14 @@ class MutatorOperatorCall extends OperatorCall { * } * ``` */ -class DelegateCall extends Call, @delegate_invocation_expr { - override Callable getTarget() { none() } - +class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr { /** * Gets a potential run-time target of this delegate call in the given * call context `cc`. */ - Callable getARuntimeTarget(CallContext::CallContext cc) { + override Callable getARuntimeTarget(CallContext::CallContext cc) { exists(DelegateCallExpr call | - this = call.getDelegateCall() and + this = call.getCall() and result = call.getARuntimeTarget(cc) ) or @@ -568,7 +598,7 @@ class DelegateCall extends Call, @delegate_invocation_expr { } private AddEventSource getAnAddEventSource(Callable enclosingCallable) { - this.getDelegateExpr().(EventAccess).getTarget() = result.getEvent() and + this.getExpr().(EventAccess).getTarget() = result.getEvent() and enclosingCallable = result.getExpr().getEnclosingCallable() } @@ -580,25 +610,12 @@ class DelegateCall extends Call, @delegate_invocation_expr { exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable()) } - override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } - - override Expr getRuntimeArgument(int i) { result = getArgument(i) } - /** - * Gets the delegate expression of this delegate call. For example, the - * delegate expression of `X()` on line 5 is the access to the field `X` in + * DEPRECATED: use `getExpr` instead. * - * ```csharp - * class A { - * Action X = () => { }; - * - * void CallX() { - * X(); - * } - * } - * ``` + * Gets the delegate expression of this call. */ - Expr getDelegateExpr() { result = this.getChild(-1) } + deprecated Expr getDelegateExpr() { result = this.getExpr() } override string toString() { result = "delegate call" } @@ -616,27 +633,18 @@ class DelegateCall extends Call, @delegate_invocation_expr { * } * ``` */ -class FunctionPointerCall extends Call, @function_pointer_invocation_expr { - override Callable getTarget() { none() } - +class FunctionPointerCall extends DelegateLikeCall, @function_pointer_invocation_expr { /** * Gets a potential run-time target of this function pointer call in the given * call context `cc`. */ - Callable getARuntimeTarget(CallContext::CallContext cc) { + override Callable getARuntimeTarget(CallContext::CallContext cc) { exists(FunctionPointerCallExpr call | - this = call.getFunctionPointerCall() and + this = call.getCall() and result = call.getARuntimeTarget(cc) ) } - override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } - - override Expr getRuntimeArgument(int i) { result = getArgument(i) } - - /** Gets the function pointer expression of this call. */ - Expr getFunctionPointerExpr() { result = this.getChild(-1) } - override string toString() { result = "function pointer call" } override string getAPrimaryQlClass() { result = "FunctionPointerCall" } diff --git a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll index 272b56093f6..0da867e116a 100644 --- a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll +++ b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll @@ -78,7 +78,7 @@ predicate depends(ValueOrRefType t, ValueOrRefType u) { or exists(DelegateCall dc, DelegateType dt | dc.getEnclosingCallable().getDeclaringType() = t and - dc.getDelegateExpr().getType() = dt and + dc.getExpr().getType() = dt and usesType(dt.getUnboundDeclaration(), u) ) or diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs index 68a91d02698..59c1c924a80 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.cs @@ -116,12 +116,12 @@ class DelegateFlow public unsafe void M17() { - M16(&M2, (i) => {}); // MISSING: a(0) in M2 is calling this lambda + M16(&M2, (i) => { }); } public unsafe void M18() { delegate*, void> fnptr = &M2; - fnptr((i) => {}); // MISSING: a(0) in M2 is calling this lambda + fnptr((i) => { }); } } diff --git a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected index 9b572b699d0..80ae0d0fe89 100644 --- a/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/delegates/DelegateFlow.expected @@ -7,6 +7,8 @@ delegateCall | DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:16:12:16:19 | (...) => ... | DelegateFlow.cs:16:12:16:19 | (...) => ... | | DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:27:12:27:19 | (...) => ... | DelegateFlow.cs:22:12:22:12 | access to parameter a | | DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:98:9:98:37 | LocalFunction | DelegateFlow.cs:99:12:99:24 | delegate creation of type Action | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:119:18:119:27 | (...) => ... | DelegateFlow.cs:114:15:114:15 | access to parameter a | +| DelegateFlow.cs:9:9:9:12 | delegate call | DelegateFlow.cs:125:15:125:24 | (...) => ... | DelegateFlow.cs:125:15:125:24 | (...) => ... | | DelegateFlow.cs:11:9:11:12 | delegate call | DelegateFlow.cs:10:13:10:20 | (...) => ... | file://:0:0:0:0 | | | DelegateFlow.cs:33:9:33:13 | delegate call | DelegateFlow.cs:38:12:38:25 | (...) => ... | DelegateFlow.cs:38:12:38:25 | (...) => ... | | DelegateFlow.cs:38:19:38:22 | delegate call | DelegateFlow.cs:5:10:5:11 | M1 | DelegateFlow.cs:33:12:33:12 | access to parameter a | diff --git a/csharp/ql/test/library-tests/expressions/DelegateCall1.ql b/csharp/ql/test/library-tests/expressions/DelegateCall1.ql index 430d2fdc43a..8d8f818a9e6 100644 --- a/csharp/ql/test/library-tests/expressions/DelegateCall1.ql +++ b/csharp/ql/test/library-tests/expressions/DelegateCall1.ql @@ -9,7 +9,7 @@ where m.hasName("MainDelegateAndMethodAccesses") and e.getEnclosingCallable() = m and e.getNumberOfArguments() = 1 and - e.getDelegateExpr() = a and + e.getExpr() = a and a.getTarget().hasName("cd1") and e.getArgument(0).getValue() = "-40" select m, e, a diff --git a/csharp/ql/test/library-tests/expressions/DelegateCall2.ql b/csharp/ql/test/library-tests/expressions/DelegateCall2.ql index 4fb915f3086..fee6f1c703a 100644 --- a/csharp/ql/test/library-tests/expressions/DelegateCall2.ql +++ b/csharp/ql/test/library-tests/expressions/DelegateCall2.ql @@ -9,7 +9,7 @@ where m.hasName("MainDelegateAndMethodAccesses") and e.getEnclosingCallable() = m and e.getNumberOfArguments() = 1 and - e.getDelegateExpr() = a and + e.getExpr() = a and a.getTarget().hasName("cd7") and e.getArgument(0).(AddExpr).getRightOperand().(LocalVariableAccess).getTarget().hasName("x") select m, e, a diff --git a/csharp/ql/test/library-tests/expressions/DelegateCall3.ql b/csharp/ql/test/library-tests/expressions/DelegateCall3.ql index 5702cad683a..b68b35dde45 100644 --- a/csharp/ql/test/library-tests/expressions/DelegateCall3.ql +++ b/csharp/ql/test/library-tests/expressions/DelegateCall3.ql @@ -8,7 +8,7 @@ from Method m, DelegateCall e, LocalVariableAccess a where m.hasName("MainDelegateAndMethodAccesses") and e.getEnclosingCallable() = m and - e.getDelegateExpr() = a and + e.getExpr() = a and a.getTarget().hasName("cd7") and a.getTarget().getType().(DelegateType).hasQualifiedName("Expressions.D") select m, e, a diff --git a/csharp/ql/test/library-tests/expressions/EventAccess3.ql b/csharp/ql/test/library-tests/expressions/EventAccess3.ql index 741f973b221..56d5cb1beb9 100644 --- a/csharp/ql/test/library-tests/expressions/EventAccess3.ql +++ b/csharp/ql/test/library-tests/expressions/EventAccess3.ql @@ -11,7 +11,7 @@ where e.getTarget().getName() = "Click" and e.getTarget().getDeclaringType() = m.getDeclaringType() and d.getEnclosingCallable() = m and - d.getDelegateExpr() = e and + d.getExpr() = e and d.getArgument(0) instanceof ThisAccess and d.getArgument(1).(ParameterAccess).getTarget().hasName("e") select m, d, e From b8194bd1f806dc43e459d073690ead4d9cda2fa1 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 1 Feb 2021 14:38:59 +0100 Subject: [PATCH 070/429] Python: Add support for API graphs Currently only supports the "use" side of things. For the most part, this follows the corresponding implementation for JavaScript. Major differences include: - No `MkImportUse` nodes -- we just move directly from `MkModuleImport` to its uses. - Paths are no longer labelled by s-expressions, but rather by a string that mirrors how you would access it in QL. This makes it very easy to see how to access an API component -- simply look at its `toString`! This PR also extends `LocalSourceNode` to support looking up attribute references and invocations of such nodes. This was again based on the JavaScript equivalent (though without specific classes for `InvokeNode` and the like, it's a bit more awkward to use). --- python/ql/src/semmle/python/ApiGraphs.qll | 343 ++++++++++++++++++ .../dataflow/new/internal/DataFlowPublic.qll | 82 ++++- 2 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 python/ql/src/semmle/python/ApiGraphs.qll diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll new file mode 100644 index 00000000000..fbee343b623 --- /dev/null +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -0,0 +1,343 @@ +import python +import semmle.python.dataflow.new.DataFlow + +module API { + class Node extends Impl::TApiNode { + /** + * Gets a data-flow node corresponding to a use of the API component represented by this node. + * + * For example, `import re; re.escape` is a use of the `escape` function from the + * `re` module, and `import re; re.escape("hello")` is a use of the return of that function. + * + * This includes indirect uses found via data flow, meaning that in + * ```python + * def f(x): + * pass + * + * f(obj.foo) + * ``` + * both `obj.foo` and `x` are uses of the `foo` member from `obj`. + */ + DataFlow::Node getAUse() { + exists(DataFlow::LocalSourceNode src | Impl::use(this, src) | + Impl::trackUseNode(src).flowsTo(result) + ) + } + + /** + * Gets an immediate use of the API component represented by this node. + * + * For example, `import re; re.escape` is a an immediate use of the `escape` member + * from the `re` module. + * + * Unlike `getAUse()`, this predicate only gets the immediate references, not the indirect uses + * found via data flow. This means that in `x = re.escape` only `re.escape` is a reference + * to the `escape` member of `re`, neither `x` nor any node that `x` flows to is a reference to + * this API component. + */ + DataFlow::LocalSourceNode getAnImmediateUse() { Impl::use(this, result) } + + /** + * Gets a call to the function represented by this API component. + */ + DataFlow::Node getACall() { result = getReturn().getAnImmediateUse() } + + /** + * Gets a node representing member `m` of this API component. + * + * For example, modules have an `exports` member representing their exports, and objects have + * their properties as members. + */ + bindingset[m] + bindingset[result] + Node getMember(string m) { result = getASuccessor(Label::member(m)) } + + /** + * Gets a node representing a member of this API component where the name of the member is + * not known statically. + */ + Node getUnknownMember() { result = getASuccessor(Label::unknownMember()) } + + /** + * Gets a node representing a member of this API component where the name of the member may + * or may not be known statically. + */ + Node getAMember() { + result = getASuccessor(Label::member(_)) or + result = getUnknownMember() + } + + /** + * Gets a node representing the result of the function represented by this node. + * + * This predicate may have multiple results when there are multiple invocations of this API component. + * Consider using `getACall()` if there is a need to distingiush between individual calls. + */ + Node getReturn() { result = getASuccessor(Label::return()) } + + /** + * 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 = getAPath(Impl::distanceFromRoot(this)) | p) } + + /** + * 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(string lbl) { Impl::edge(this, lbl, result) } + + /** + * 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(string lbl) { this = result.getASuccessor(lbl) } + + /** + * Gets a node such that there is an edge in the API graph between this node and the other + * one. + */ + Node getAPredecessor() { result = getAPredecessor(_) } + + /** + * Gets a node such that there is an edge in the API graph between that other node and + * this one. + */ + Node getASuccessor() { result = getASuccessor(_) } + + /** + * Gets the data-flow node that gives rise to this node, if any. + */ + DataFlow::Node getInducingNode() { this = Impl::MkUse(result) } + + /** + * Holds if this node is located in file `path` between line `startline`, column `startcol`, + * and line `endline`, column `endcol`. + * + * For nodes that do not have a meaningful location, `path` is the empty string and all other + * parameters are zero. + */ + predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) { + getInducingNode().hasLocationInfo(path, startline, startcol, endline, endcol) + or + not exists(getInducingNode()) and + path = "" and + startline = 0 and + startcol = 0 and + endline = 0 and + endcol = 0 + } + + /** + * Gets a textual representation of this node. + */ + string toString() { + none() // defined in subclasses + } + + /** + * 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, string lbl, string predpath | + Impl::edge(pred, lbl, this) and + lbl != "" 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) } + } + + /** The root node of an API graph. */ + class Root extends Node, Impl::MkRoot { + override string toString() { result = "root" } + } + + /** A node corresponding to the use of an API component. */ + class Use extends Node, Impl::TUse { + override string toString() { + exists(string type | + this = Impl::MkUse(_) and type = "Use " + or + this = Impl::MkModuleImport(_) and type = "ModuleImport " + | + result = type + getPath() + or + not exists(this.getPath()) and result = type + "with no path" + ) + } + } + + /** Gets the root node. */ + Root root() { any() } + + /** Gets a node corresponding to an import of module `m`. */ + Node moduleImport(string m) { result = Impl::MkModuleImport(m) } + + /** + * 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. + */ + cached + private module Impl { + cached + newtype TApiNode = + /** The root of the API graph. */ + MkRoot() or + /** An abstract representative for imports of the module called `name`. */ + MkModuleImport(string name) { imports(_, name) } or + /** A use of an API member at the node `nd`. */ + MkUse(DataFlow::Node nd) { use(_, _, nd) } + + class TUse = MkModuleImport or MkUse; + + /** Holds if `imp` is an import of a module named `name` */ + private predicate imports(DataFlow::Node imp, string name) { imp = DataFlow::importNode(name) } + + /** + * Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled + * `lbl` in the API graph. + */ + cached + predicate use(TApiNode base, string lbl, DataFlow::Node ref) { + exists(DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode pred | + use(base, src) and pred = trackUseNode(src) + | + lbl = Label::memberFromRef(ref) and + ref = pred.getAnAttributeRead() + or + lbl = Label::return() and + ref = pred.getAnInvocation() + ) + } + + /** + * Holds if `ref` is a use of node `nd`. + */ + cached + predicate use(TApiNode nd, DataFlow::Node ref) { + exists(string name | + nd = MkModuleImport(name) and + ref = DataFlow::importNode(name) + ) + or + nd = MkUse(ref) + } + + /** + * Gets a data-flow node to which `nd`, which is a use of an API-graph node, flows. + * + * The flow from `nd` to that node may be inter-procedural. + */ + private DataFlow::LocalSourceNode trackUseNode( + DataFlow::LocalSourceNode src, DataFlow::TypeTracker t + ) { + t.start() and + use(_, src) and + result = src + or + // Due to bad performance when using `trackUseNode(t2, attr_name).track(t2, t)` + // we have inlined that code and forced a join + exists(DataFlow::StepSummary summary | + t = trackUseNode_first_join(src, result, summary).append(summary) + ) + } + + pragma[nomagic] + private DataFlow::TypeTracker trackUseNode_first_join( + DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode res, DataFlow::StepSummary summary + ) { + DataFlow::StepSummary::step(trackUseNode(src, result), res, summary) + } + + cached + DataFlow::LocalSourceNode trackUseNode(DataFlow::LocalSourceNode src) { + result = trackUseNode(src, DataFlow::TypeTracker::end()) + } + + /** + * Holds if there is an edge from `pred` to `succ` in the API graph that is labeled with `lbl`. + */ + cached + predicate edge(Node pred, string lbl, Node succ) { + /* There's an edge from the root node for each imported module. */ + exists(string m | + pred = MkRoot() and + lbl = Label::mod(m) + | + succ = MkModuleImport(m) + ) + or + /* Every node that is a use of an API component is itself added to the API graph. */ + exists(DataFlow::LocalSourceNode ref | + use(pred, lbl, ref) and + succ = MkUse(ref) + ) + } + + /** + * 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) + } +} + +private module Label { + /** Gets the edge label for the module `m`. */ + bindingset[m] + bindingset[result] + string mod(string m) { result = "moduleImport(\"" + m + "\")" } + + /** Gets the `member` edge label for member `m`. */ + bindingset[m] + bindingset[result] + string member(string m) { result = "getMember(\"" + m + "\")" } + + /** Gets the `member` edge label for the unknown member. */ + string unknownMember() { result = "getUnknownMember()" } + + /** Gets the `member` edge label for the given attribute reference. */ + string memberFromRef(DataFlow::AttrRef pr) { + result = member(pr.getAttributeName()) + or + not exists(pr.getAttributeName()) and + result = unknownMember() + } + + /** Gets the `return` edge label. */ + string return() { result = "getReturn()" } +} diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index cb807917419..f2f90723d77 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -447,7 +447,87 @@ class LocalSourceNode extends Node { /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ cached - predicate flowsTo(Node nodeTo) { simpleLocalFlowStep*(this, nodeTo) } + predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) } + + /** + * Gets a reference (read or write) of attribute `attrName` on this node. + */ + AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) } + + /** + * Gets a read of attribute `attrName` on this node. + */ + AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) } + + /** + * Gets a reference (read or write) of any attribute on this node. + */ + AttrRef getAnAttributeReference() { + Cached::namedAttrRef(this, _, result) + or + Cached::dynamicAttrRef(this, result) + } + + /** + * Gets a read of any attribute on this node. + */ + AttrRead getAnAttributeRead() { result = getAnAttributeReference() } + + /** + * Gets an invocation (with our without `new`) of this node. + */ + Node getAnInvocation() { Cached::invocation(this, result) } +} + +cached +private module Cached { + /** + * Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps. + * + * The slightly backwards parametering ordering is to force correct indexing. + */ + cached + predicate hasLocalSource(Node sink, Node source) { + // Declaring `source` to be a `SourceNode` currently causes a redundant check in the + // recursive case, so instead we check it explicitly here. + source = sink and + source instanceof LocalSourceNode + or + exists(Node mid | + hasLocalSource(mid, source) and + simpleLocalFlowStep(mid, sink) + ) + } + + /** + * Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`. + */ + cached + predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) { + hasLocalSource(ref.getObject(), base) and + ref.getAttributeName() = attr + } + + /** + * Holds if `base` flows to the base of `ref` and `ref` has no known attribute name. + */ + cached + predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) { + hasLocalSource(ref.getObject(), base) and + not exists(ref.getAttributeName()) + } + + /** + * Holds if `func` flows to the callee of `invoke`. + */ + cached + predicate invocation(LocalSourceNode func, Node invoke) { + exists(CfgNode n, CallNode call | + invoke.asCfgNode() = call and n.asCfgNode() = call.getFunction() + | + hasLocalSource(n, func) + ) + } } /** From 384d0212b11a49dfb73ffe06e6738c5f8ed8de81 Mon Sep 17 00:00:00 2001 From: yoff Date: Mon, 1 Feb 2021 16:41:43 +0100 Subject: [PATCH 071/429] Update python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll Co-authored-by: Taus --- .../src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 694243e0e81..2ab91694217 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1260,7 +1260,7 @@ module IterableUnpacking { Expr getSource() { result = source } } - /** The LHS of an assignemnt, it also records the assigned value. */ + /** The LHS of an assignment, it also records the assigned value. */ class AssignmentTarget extends ControlFlowNode { Expr value; From cd7b013a0c084f624952796659566f4be2e300ed Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 1 Feb 2021 18:57:25 +0100 Subject: [PATCH 072/429] Python: Add missing documentation --- python/ql/src/semmle/python/ApiGraphs.qll | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index fbee343b623..2dc62ed30a6 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -1,7 +1,22 @@ +/** + * Provides an implementation of _API graphs_, which are an abstract representation of the API + * surface used and/or defined by a code base. + * + * 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. + */ + import python import semmle.python.dataflow.new.DataFlow +/** + * Provides classes and predicates for working with APIs used in a database. + */ module API { + /** + * An abstract representation of a definition or use of an API component such as a function + * exported by a Python package, or its result. + */ class Node extends Impl::TApiNode { /** * Gets a data-flow node corresponding to a use of the API component represented by this node. From 74fd2c1c3880ce5a5cdeb46d40a1bb0254791697 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 1 Feb 2021 14:57:35 +0100 Subject: [PATCH 073/429] C#: Move uncertain-read logic into shared SSA implementation --- .../code/csharp/dataflow/internal/SsaImpl.qll | 64 ++----------- .../dataflow/internal/SsaImplCommon.qll | 92 ++++++++++++++++--- .../dataflow/internal/SsaImplSpecific.qll | 2 +- 3 files changed, 90 insertions(+), 68 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll index d51122ef568..5e25c1ea0a4 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -954,10 +954,12 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou * * This includes implicit reads via calls. */ -predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v) { - variableReadActual(bb, i, v) +predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) { + variableReadActual(bb, i, v) and + certain = true or - variableReadPseudo(bb, i, v) + variableReadPseudo(bb, i, v) and + certain = false } cached @@ -1107,26 +1109,6 @@ private module Cached { ssaDefReachesEndOfBlock(bb, def, _) } - private predicate adjacentDefReaches( - Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 - ) { - adjacentDefRead(def, bb1, i1, bb2, i2) - or - exists(ControlFlow::BasicBlock bb3, int i3 | - adjacentDefReaches(def, bb1, i1, bb3, i3) and - variableReadPseudo(bb3, i3, _) and - adjacentDefRead(def, bb3, i3, bb2, i2) - ) - } - - pragma[noinline] - private predicate adjacentDefActualRead( - Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 - ) { - adjacentDefReaches(def, bb1, i1, bb2, i2) and - variableReadActual(bb2, i2, _) - } - cached AssignableRead getAReadAtNode(Definition def, ControlFlow::Node cfn) { exists(Ssa::SourceVariable v, ControlFlow::BasicBlock bb, int i | @@ -1145,7 +1127,7 @@ private module Cached { predicate firstReadSameVar(Definition def, ControlFlow::Node cfn) { exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 | def.definesAt(_, bb1, i1) and - adjacentDefActualRead(def, bb1, i1, bb2, i2) and + adjacentDefNoUncertainReads(def, bb1, i1, bb2, i2) and cfn = bb2.getNode(i2) ) } @@ -1160,48 +1142,20 @@ private module Cached { exists(ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 | cfn1 = bb1.getNode(i1) and variableReadActual(bb1, i1, _) and - adjacentDefActualRead(def, bb1, i1, bb2, i2) and + adjacentDefNoUncertainReads(def, bb1, i1, bb2, i2) and cfn2 = bb2.getNode(i2) ) } - private predicate adjacentDefPseudoRead( - Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2 - ) { - adjacentDefReaches(def, bb1, i1, bb2, i2) and - variableReadPseudo(bb2, i2, _) - } - - private predicate reachesLastRefRedef( - Definition def, ControlFlow::BasicBlock bb, int i, Definition next - ) { - lastRefRedef(def, bb, i, next) - or - exists(ControlFlow::BasicBlock bb0, int i0 | - reachesLastRefRedef(def, bb0, i0, next) and - adjacentDefPseudoRead(def, bb, i, bb0, i0) - ) - } - cached predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) { - reachesLastRefRedef(def, bb, i, next) and - not variableReadPseudo(bb, i, def.getSourceVariable()) - } - - private predicate reachesLastRef(Definition def, ControlFlow::BasicBlock bb, int i) { - lastRef(def, bb, i) - or - exists(ControlFlow::BasicBlock bb0, int i0 | - reachesLastRef(def, bb0, i0) and - adjacentDefPseudoRead(def, bb, i, bb0, i0) - ) + lastRefRedefNoUncertainReads(def, bb, i, next) } cached predicate lastReadSameVar(Definition def, ControlFlow::Node cfn) { exists(ControlFlow::BasicBlock bb, int i | - reachesLastRef(def, bb, i) and + lastRefNoUncertainReads(def, bb, i) and variableReadActual(bb, i, _) and cfn = bb.getNode(i) ) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll index f4cb01f7a97..2257994c2e0 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll @@ -17,18 +17,18 @@ private module Liveness { * (certain or uncertain) writes. */ private newtype TRefKind = - Read() or - Write(boolean certain) { certain = true or certain = false } + Read(boolean certain) { certain in [false, true] } or + Write(boolean certain) { certain in [false, true] } private class RefKind extends TRefKind { string toString() { - this = Read() and result = "read" + exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") or exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") } int getOrder() { - this = Read() and + this = Read(_) and result = 0 or this = Write(_) and @@ -40,7 +40,7 @@ private module Liveness { * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. */ private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { - variableRead(bb, i, v) and k = Read() + exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) or exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) } @@ -95,7 +95,7 @@ private module Liveness { */ predicate liveAtEntry(BasicBlock bb, SourceVariable v) { // The first read or certain write to `v` inside `bb` is a read - refRank(bb, _, v, Read()) = firstReadOrCertainWrite(bb, v) + refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) or // There is no certain write to `v` inside `bb`, but `v` is live at entry // to a successor basic block of `bb` @@ -120,7 +120,7 @@ private module Liveness { liveAtExit(bb, v) or ref(bb, i, v, kind) and - kind = Read() + kind = Read(_) or exists(RefKind nextKind | liveAtRank(bb, _, v, rnk + 1) and @@ -237,7 +237,7 @@ private module SsaDefReaches { * Unlike `Liveness::ref`, this includes `phi` nodes. */ predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { - variableRead(bb, i, v) and + variableRead(bb, i, v, _) and k = SsaRead() or exists(Definition def | def.definesAt(v, bb, i)) and @@ -304,7 +304,7 @@ private module SsaDefReaches { exists(int rnk | ssaDefReachesRank(bb, def, rnk, v) and rnk = ssaRefRank(bb, i, v, SsaRead()) and - variableRead(bb, i, v) + variableRead(bb, i, v, _) ) } @@ -368,7 +368,7 @@ private module SsaDefReaches { predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { varBlockReaches(def, bb1, bb2) and ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and - variableRead(bb2, i2, _) + variableRead(bb2, i2, _, _) } } @@ -394,6 +394,7 @@ private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, Sour * block `bb`, at which point it is still live, without crossing another * SSA definition of `v`. */ +pragma[nomagic] predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { exists(int last | last = maxSsaRefRank(bb, v) | ssaDefReachesRank(bb, def, last, v) and @@ -412,10 +413,11 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable * basic block `bb`, without crossing another SSA definition of `v`. The read * is of kind `rk`. */ +pragma[nomagic] predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { ssaDefReachesReadWithinBlock(v, def, bb, i) or - variableRead(bb, i, v) and + variableRead(bb, i, v, _) and ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and not ssaDefReachesReadWithinBlock(v, _, bb, i) } @@ -427,11 +429,12 @@ predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a * path between them without any read of `def`. */ +pragma[nomagic] predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { exists(int rnk | rnk = ssaDefRank(def, _, bb1, i1, _) and rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and - variableRead(bb1, i2, _) and + variableRead(bb1, i2, _, _) and bb2 = bb1 ) or @@ -439,6 +442,30 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2 defAdjacentRead(def, bb1, bb2, i2) } +private predicate adjacentDefReachesRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefRead(def, bb1, i1, bb2, i2) and + not variableRead(bb1, i1, def.getSourceVariable(), false) + or + exists(BasicBlock bb3, int i3 | + adjacentDefReachesRead(def, bb1, i1, bb3, i3) and + variableRead(bb3, i3, _, false) and + adjacentDefRead(def, bb3, i3, bb2, i2) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `adjacentDefRead`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, true) +} + /** * NB: If this predicate is exposed, it should be cached. * @@ -446,6 +473,7 @@ predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2 * `def`. The reference is last because it can reach another write `next`, * without passing through another read or write. */ +pragma[nomagic] predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) | // Next reference to `v` inside `bb` is a write @@ -462,6 +490,29 @@ predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { ) } +private predicate adjacentDefReachesUncertainRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, false) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { + lastRefRedef(def, bb, i, next) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRefRedef(def, bb0, i0, next) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + /** * NB: If this predicate is exposed, it should be cached. * @@ -472,6 +523,7 @@ predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { * SSA definition for the underlying source variable, without passing through * another read. */ +pragma[nomagic] predicate lastRef(Definition def, BasicBlock bb, int i) { lastRefRedef(def, bb, i, _) or @@ -487,6 +539,22 @@ predicate lastRef(Definition def, BasicBlock bb, int i) { ) } +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { + lastRef(def, bb, i) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRef(def, bb0, i0) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + /** A static single assignment (SSA) definition. */ class Definition extends TDefinition { /** Gets the source variable underlying this SSA definition. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll index c99ad7d8fb3..2091b73c388 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplSpecific.qll @@ -16,4 +16,4 @@ class SourceVariable = SsaImpl::TSourceVariable; predicate variableWrite = SsaImpl::variableWrite/4; -predicate variableRead = SsaImpl::variableRead/3; +predicate variableRead = SsaImpl::variableRead/4; From b19fd7bb7278302bfd707947c96ed16c29896746 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 2 Feb 2021 10:42:32 +0100 Subject: [PATCH 074/429] C#: Only cache `TDefinition` in the shared SSA implementation --- .../src/semmle/code/csharp/dataflow/SSA.qll | 33 +++++-- .../code/csharp/dataflow/internal/SsaImpl.qll | 12 ++- .../dataflow/internal/SsaImplCommon.qll | 97 ++++++++----------- 3 files changed, 77 insertions(+), 65 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll index 0bd7e848639..44307d68e1f 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/SSA.qll @@ -384,9 +384,18 @@ module Ssa { result.getAControlFlowNode() = cfn } + /** + * Gets an SSA definition whose value can flow to this one in one step. This + * includes inputs to phi nodes and the prior definitions of uncertain writes. + */ + private Definition getAPhiInputOrPriorDefinition() { + result = this.(PhiNode).getAnInput() or + result = this.(UncertainDefinition).getPriorDefinition() + } + /** * Gets a definition that ultimately defines this SSA definition and is - * not itself a pseudo node. Example: + * not itself a phi node. Example: * * ```csharp * int Field; @@ -413,8 +422,9 @@ module Ssa { * definition on line 4, the explicit definition on line 7, and the implicit * definition on line 9. */ - final override Definition getAnUltimateDefinition() { - result = SsaImpl::Definition.super.getAnUltimateDefinition() + final Definition getAnUltimateDefinition() { + result = this.getAPhiInputOrPriorDefinition*() and + not result instanceof PhiNode } /** @@ -425,7 +435,7 @@ module Ssa { /** * Gets the syntax element associated with this SSA definition, if any. * This is either an expression, for example `x = 0`, a parameter, or a - * callable. Pseudo nodes have no associated syntax element. + * callable. Phi nodes have no associated syntax element. */ Element getElement() { result = this.getControlFlowNode().getElement() } @@ -681,7 +691,12 @@ module Ssa { * definition on line 4, the explicit definition on line 7, and the implicit * call definition on line 9 as inputs. */ - final override Definition getAnInput() { result = SsaImpl::PhiNode.super.getAnInput() } + final Definition getAnInput() { this.hasInputFromBlock(result, _) } + + /** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */ + predicate hasInputFromBlock(Definition inp, ControlFlow::BasicBlock bb) { + inp = SsaImpl::phiHasInputFromBlock(this, bb) + } override string toString() { result = getToStringPrefix(this) + "SSA phi(" + getSourceVariable() + ")" @@ -704,5 +719,11 @@ module Ssa { * need not be certain), an implicit non-local update via a call, or an * uncertain update of the qualifier. */ - class UncertainDefinition extends Definition, SsaImpl::UncertainWriteDefinition { } + class UncertainDefinition extends Definition, SsaImpl::UncertainWriteDefinition { + /** + * Gets the immediately preceding definition. Since this update is uncertain, + * the value from the preceding definition might still be valid. + */ + Definition getPriorDefinition() { result = SsaImpl::uncertainWriteDefinitionInput(this) } + } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll index 5e25c1ea0a4..eff99d351c4 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -1075,7 +1075,7 @@ private module Cached { Ssa::ExplicitDefinition def, Ssa::ImplicitEntryDefinition edef, ControlFlow::Nodes::ElementNode c, boolean additionalCalls ) { - exists(Ssa::SourceVariable v, Definition def0, ControlFlow::BasicBlock bb, int i | + exists(Ssa::SourceVariable v, Ssa::Definition def0, ControlFlow::BasicBlock bb, int i | v = def.getSourceVariable() and capturedReadIn(_, _, v, edef.getSourceVariable(), c, additionalCalls) and def = def0.getAnUltimateDefinition() and @@ -1109,6 +1109,11 @@ private module Cached { ssaDefReachesEndOfBlock(bb, def, _) } + cached + Definition phiHasInputFromBlock(PhiNode phi, ControlFlow::BasicBlock bb) { + phiHasInputFromBlock(phi, result, bb) + } + cached AssignableRead getAReadAtNode(Definition def, ControlFlow::Node cfn) { exists(Ssa::SourceVariable v, ControlFlow::BasicBlock bb, int i | @@ -1161,6 +1166,11 @@ private module Cached { ) } + cached + Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) { + uncertainWriteDefinitionInput(def, result) + } + cached predicate isLiveOutRefParameterDefinition(Ssa::Definition def, Parameter p) { p.isOutOrRef() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll index 2257994c2e0..be01c05b8fa 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll @@ -174,35 +174,16 @@ private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { } cached -private module Cached { - cached - newtype TDefinition = - TWriteDef(SourceVariable v, BasicBlock bb, int i) { - variableWrite(bb, i, v, _) and - liveAfterWrite(bb, i, v) - } or - TPhiNode(SourceVariable v, BasicBlock bb) { - inDefDominanceFrontier(bb, v) and - liveAtEntry(bb, v) - } - - cached - predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { - lastRefRedef(inp, _, _, def) +newtype TDefinition = + TWriteDef(SourceVariable v, BasicBlock bb, int i) { + variableWrite(bb, i, v, _) and + liveAfterWrite(bb, i, v) + } or + TPhiNode(SourceVariable v, BasicBlock bb) { + inDefDominanceFrontier(bb, v) and + liveAtEntry(bb, v) } - cached - predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { - exists(SourceVariable v, BasicBlock bbDef | - phi.definesAt(v, bbDef, _) and - getABasicBlockPredecessor(bbDef) = bb and - ssaDefReachesEndOfBlock(bb, inp, v) - ) - } -} - -import Cached - private module SsaDefReaches { newtype TSsaRefKind = SsaRead() or @@ -406,6 +387,20 @@ predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable not ssaRef(bb, _, v, SsaDef()) } +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. + */ +pragma[nomagic] +predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { + exists(SourceVariable v, BasicBlock bbDef | + phi.definesAt(v, bbDef, _) and + getABasicBlockPredecessor(bbDef) = bb and + ssaDefReachesEndOfBlock(bb, inp, v) + ) +} + /** * NB: If this predicate is exposed, it should be cached. * @@ -446,7 +441,11 @@ private predicate adjacentDefReachesRead( Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 ) { adjacentDefRead(def, bb1, i1, bb2, i2) and - not variableRead(bb1, i1, def.getSourceVariable(), false) + exists(SourceVariable v | v = def.getSourceVariable() | + ssaRef(bb1, i1, v, SsaDef()) + or + variableRead(bb1, i1, v, true) + ) or exists(BasicBlock bb3, int i3 | adjacentDefReachesRead(def, bb1, i1, bb3, i3) and @@ -490,6 +489,18 @@ predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { ) } +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an immediately preceding definition of uncertain definition + * `def`. Since `def` is uncertain, the value from the preceding definition might + * still be valid. + */ +pragma[nomagic] +predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { + lastRefRedef(inp, _, _, def) +} + private predicate adjacentDefReachesUncertainRead( Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 ) { @@ -574,24 +585,6 @@ class Definition extends TDefinition { /** Gets the basic block to which this SSA definition belongs. */ final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } - /** - * Gets an SSA definition whose value can flow to this one in one step. This - * includes inputs to phi nodes and the prior definitions of uncertain writes. - */ - private Definition getAPseudoInputOrPriorDefinition() { - result = this.(PhiNode).getAnInput() or - result = this.(UncertainWriteDefinition).getPriorDefinition() - } - - /** - * Gets a definition that ultimately defines this SSA definition and is - * not itself a phi node. - */ - Definition getAnUltimateDefinition() { - result = this.getAPseudoInputOrPriorDefinition*() and - not result instanceof PhiNode - } - /** Gets a textual representation of this SSA definition. */ string toString() { none() } } @@ -609,12 +602,6 @@ class WriteDefinition extends Definition, TWriteDef { /** A phi node. */ class PhiNode extends Definition, TPhiNode { - /** Gets an input of this phi node. */ - Definition getAnInput() { this.hasInputFromBlock(result, _) } - - /** Holds if `inp` is an input to the phi node along the edge originating in `bb`. */ - predicate hasInputFromBlock(Definition inp, BasicBlock bb) { phiHasInputFromBlock(this, inp, bb) } - override string toString() { result = "Phi" } } @@ -629,10 +616,4 @@ class UncertainWriteDefinition extends WriteDefinition { variableWrite(bb, i, v, false) ) } - - /** - * Gets the immediately preceding definition. Since this update is uncertain, - * the value from the preceding definition might still be valid. - */ - Definition getPriorDefinition() { uncertainWriteDefinitionInput(this, result) } } From d046e39a826b2fcb247a1d615811549d0e7cb2d8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 2 Feb 2021 12:04:24 +0100 Subject: [PATCH 075/429] Python: Fix tornado inline expectations in tests After merge commit --- .../library-tests/frameworks/tornado/response_test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/tornado/response_test.py b/python/ql/test/experimental/library-tests/frameworks/tornado/response_test.py index d8af7f3895a..42cd37c2118 100644 --- a/python/ql/test/experimental/library-tests/frameworks/tornado/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/tornado/response_test.py @@ -33,7 +33,8 @@ class ExplicitContentType(tornado.web.RequestHandler): class ExampleRedirect(tornado.web.RequestHandler): def get(self): # $ requestHandler - self.redirect("http://example.com") # TODO: Model redirect + url = "http://example.com" + self.redirect(url) # $ HttpRedirectResponse HttpResponse redirectLocation=url class ExampleConnectionWrite(tornado.web.RequestHandler): From 64f0dfb17452a8a0842410ad0fd7c1aa30541b65 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 2 Feb 2021 14:21:26 +0100 Subject: [PATCH 076/429] Fix code review findings --- .../code/csharp/dataflow/CallContext.qll | 8 +--- .../dataflow/internal/DataFlowDispatch.qll | 10 ++--- .../dataflow/internal/DataFlowPrivate.qll | 2 +- .../dataflow/internal/DelegateDataFlow.qll | 41 +++++++------------ .../ql/src/semmle/code/csharp/exprs/Call.qll | 27 +++++------- 5 files changed, 32 insertions(+), 56 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll index aa501a58e0d..8be2fc0939f 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/CallContext.qll @@ -82,12 +82,8 @@ class DelegateLikeCallArgumentCallContext extends ArgumentCallContext { /** An argument of a delegate call. */ class DelegateCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, - TArgDelegateCallContext { - DelegateCallArgumentCallContext() { this = TArgDelegateCallContext(dc, arg) } -} + TArgDelegateCallContext { } /** An argument of a function pointer call. */ class FunctionPointerCallArgumentCallContext extends DelegateLikeCallArgumentCallContext, - TArgFunctionPointerCallContext { - FunctionPointerCallArgumentCallContext() { this = TArgFunctionPointerCallContext(dc, arg) } -} + TArgFunctionPointerCallContext { } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll index 2337f2ec349..c68ba38e0b5 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowDispatch.qll @@ -101,7 +101,7 @@ private module Cached { TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) { cfn.getElement() = dc.getCall() } or - TExplicitDelegateCall(ControlFlow::Nodes::ElementNode cfn, DelegateCall dc) { + TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) { cfn.getElement() = dc } or TTransitiveCapturedCall(ControlFlow::Nodes::ElementNode cfn, Callable target) { @@ -308,12 +308,12 @@ abstract class DelegateDataFlowCall extends DataFlowCall { override DataFlowCallable getARuntimeTarget() { result = this.getARuntimeTarget(_) } } -/** An explicit delegate call relevant for data flow. */ -class ExplicitDelegateDataFlowCall extends DelegateDataFlowCall, TExplicitDelegateCall { +/** An explicit delegate or function pointer call relevant for data flow. */ +class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDelegateLikeCall { private ControlFlow::Nodes::ElementNode cfn; - private DelegateCall dc; + private DelegateLikeCall dc; - ExplicitDelegateDataFlowCall() { this = TExplicitDelegateCall(cfn, dc) } + ExplicitDelegateLikeDataFlowCall() { this = TExplicitDelegateLikeCall(cfn, dc) } override DataFlowCallable getARuntimeTarget(CallContext::CallContext cc) { result = getCallableForDataFlow(dc.getARuntimeTarget(cc)) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 5446323543a..64452768185 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1394,7 +1394,7 @@ private module OutNodes { private DataFlowCall csharpCall(Expr e, ControlFlow::Node cfn) { e = any(DispatchCall dc | result = TNonDelegateCall(cfn, dc)).getCall() or - result = TExplicitDelegateCall(cfn, e) + result = TExplicitDelegateLikeCall(cfn, e) } /** A valid return type for a method that uses `yield return`. */ diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll index af70cb19654..e6b15b95d7f 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DelegateDataFlow.qll @@ -15,9 +15,9 @@ private import semmle.code.csharp.dispatch.Dispatch private import semmle.code.csharp.frameworks.system.linq.Expressions /** A source of flow for a delegate or function pointer expression. */ -private class DelegateLikeFlowSource extends DataFlow::ExprNode { +abstract private class DelegateLikeFlowSource extends DataFlow::ExprNode { /** Gets the callable that is referenced in this delegate or function pointer flow source. */ - Callable getCallable() { none() } + abstract Callable getCallable(); } /** A source of flow for a delegate expression. */ @@ -41,10 +41,13 @@ private class FunctionPointerFlowSource extends DelegateLikeFlowSource { Callable c; FunctionPointerFlowSource() { - this.getExpr() = - any(Expr e | - c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration() - ) + c = + this.getExpr() + .(AddressOfExpr) + .getOperand() + .(CallableAccess) + .getTarget() + .getUnboundDeclaration() } /** Gets the callable that is referenced in this function pointer flow source. */ @@ -115,28 +118,12 @@ abstract private class DelegateLikeFlowSink extends DataFlow::Node { /** A delegate or function pointer call expression. */ class DelegateLikeCallExpr extends DelegateLikeFlowSink, DataFlow::ExprNode { + DelegateLikeCall dc; + + DelegateLikeCallExpr() { this.getExpr() = dc.getExpr() } + /** Gets the delegate or function pointer call that this expression belongs to. */ - DelegateLikeCall getCall() { none() } -} - -/** A delegate call expression. */ -class DelegateCallExpr extends DelegateLikeCallExpr { - DelegateCall dc; - - DelegateCallExpr() { this.getExpr() = dc.getExpr() } - - /** Gets the delegate call that this expression belongs to. */ - override DelegateCall getCall() { result = dc } -} - -/** A function pointer call expression. */ -class FunctionPointerCallExpr extends DelegateLikeCallExpr { - FunctionPointerCall fptrc; - - FunctionPointerCallExpr() { this.getExpr() = fptrc.getExpr() } - - /** Gets the function pointer call that this expression belongs to. */ - override FunctionPointerCall getCall() { result = fptrc } + DelegateLikeCall getCall() { result = dc } } /** A parameter of delegate type belonging to a callable with a flow summary. */ diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index 941873d9afd..078ecd1a52a 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -527,17 +527,24 @@ class MutatorOperatorCall extends OperatorCall { predicate isPostfix() { mutator_invocation_mode(this, 2) } } +private class DelegateLikeCall_ = @delegate_invocation_expr or @function_pointer_invocation_expr; + /** * A function pointer or delegate call. */ -abstract class DelegateLikeCall extends Call { +class DelegateLikeCall extends Call, DelegateLikeCall_ { override Callable getTarget() { none() } /** * Gets a potential run-time target of this delegate or function pointer call in the given * call context `cc`. */ - Callable getARuntimeTarget(CallContext::CallContext cc) { none() } + Callable getARuntimeTarget(CallContext::CallContext cc) { + exists(DelegateLikeCallExpr call | + this = call.getCall() and + result = call.getARuntimeTarget(cc) + ) + } /** * Gets the delegate or function pointer expression of this call. For example, the @@ -579,10 +586,7 @@ class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr { * call context `cc`. */ override Callable getARuntimeTarget(CallContext::CallContext cc) { - exists(DelegateCallExpr call | - this = call.getCall() and - result = call.getARuntimeTarget(cc) - ) + result = DelegateLikeCall.super.getARuntimeTarget(cc) or exists(AddEventSource aes, CallContext::CallContext cc2 | aes = this.getAnAddEventSource(_) and @@ -634,17 +638,6 @@ class DelegateCall extends DelegateLikeCall, @delegate_invocation_expr { * ``` */ class FunctionPointerCall extends DelegateLikeCall, @function_pointer_invocation_expr { - /** - * Gets a potential run-time target of this function pointer call in the given - * call context `cc`. - */ - override Callable getARuntimeTarget(CallContext::CallContext cc) { - exists(FunctionPointerCallExpr call | - this = call.getCall() and - result = call.getARuntimeTarget(cc) - ) - } - override string toString() { result = "function pointer call" } override string getAPrimaryQlClass() { result = "FunctionPointerCall" } From 50be54385a6a0ab4d7219c350bd16d1f7e9f1f12 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Tue, 2 Feb 2021 14:49:50 +0000 Subject: [PATCH 077/429] Update qldoc --- .../Security/CWE/CWE-326/InsufficientKeySize.java | 4 ++-- java/ql/src/semmle/code/java/security/Encryption.qll | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java index 6ccf025c244..ff30196abb5 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.java @@ -25,12 +25,12 @@ public class InsufficientKeySize { keyPairGen4.initialize(2048); KeyPairGenerator keyPairGen5 = KeyPairGenerator.getInstance("EC"); - // BAD: Key size is less than 224 + // BAD: Key size is less than 256 ECGenParameterSpec ecSpec1 = new ECGenParameterSpec("secp112r1"); keyPairGen5.initialize(ecSpec1); KeyPairGenerator keyPairGen6 = KeyPairGenerator.getInstance("EC"); - // GOOD: Key size is no less than 224 + // GOOD: Key size is no less than 256 ECGenParameterSpec ecSpec2 = new ECGenParameterSpec("secp256r1"); keyPairGen6.initialize(ecSpec2); } diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index 9c10569d8c1..ddbaf9cba73 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -315,7 +315,7 @@ class JavaSecuritySignature extends JavaSecurityAlgoSpec { override Expr getAlgoSpec() { result = this.(ConstructorCall).getArgument(0) } } -/** Method call to the Java class `java.security.KeyPairGenerator`. */ +/** A method call to the Java class `java.security.KeyPairGenerator`. */ class JavaSecurityKeyPairGenerator extends JavaxCryptoAlgoSpec { JavaSecurityKeyPairGenerator() { exists(Method m | m.getAReference() = this | From 5e3b6fa3415d899c6bf2dea25de011244d563cee Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Tue, 2 Feb 2021 16:20:39 +0000 Subject: [PATCH 078/429] Update qldoc --- .../experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp index 10ec6adc9df..4d4ec76f060 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-326/InsufficientKeySize.qhelp @@ -6,7 +6,7 @@ are vulnerable to brute force attack when too small a key size is used.

    -

    The key should be at least 2048 bits long when using RSA and DSA encryption, 224 bits long when using EC encryption, and 128 bits long when using +

    The key should be at least 2048 bits long when using RSA and DSA encryption, 256 bits long when using EC encryption, and 128 bits long when using symmetric encryption.

    From 3151aeff48c41c067e1daea026edbe3d759b702b Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Tue, 2 Feb 2021 18:26:29 +0000 Subject: [PATCH 079/429] Enhance the query --- .../CWE/CWE-522/InsecureLdapAuth.java | 2 +- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 72 +++++++++---------- .../code/java/frameworks/Networking.qll | 1 + 3 files changed, 36 insertions(+), 39 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java index 33764506a1b..3c5f6555100 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.java @@ -15,7 +15,7 @@ public class InsecureLdapAuth { environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environment.put(Context.PROVIDER_URL, ldapUrl); environment.put(Context.REFERRAL, "follow"); - env.put(Context.SECURITY_AUTHENTICATION, "simple"); + environment.put(Context.SECURITY_AUTHENTICATION, "simple"); environment.put(Context.SECURITY_PRINCIPAL, ldapUserName); environment.put(Context.SECURITY_CREDENTIALS, password); DirContext dirContext = new InitialDirContext(environment); diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index 9563c755410..b6e7b5ed702 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -76,7 +76,7 @@ class InsecureLdapUrl extends Expr { */ predicate isProviderUrlSetter(MethodAccess ma) { ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and - (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and + ma.getMethod().hasName(["put", "setProperty"]) and ( ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "java.naming.provider.url" or @@ -89,27 +89,48 @@ predicate isProviderUrlSetter(MethodAccess ma) { } /** - * Holds if `ma` sets `fieldValue` with attribute name `fieldName` to `envValue` in some `Hashtable`. + * Holds if `ma` sets `fieldValue` to `envValue` in some `Hashtable`. */ bindingset[fieldValue, envValue] -predicate hasEnvWithValue(MethodAccess ma, string fieldValue, string envValue) { +predicate hasFieldValueEnv(MethodAccess ma, string fieldValue, string envValue) { + // environment.put("java.naming.security.authentication", "simple") ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and - (ma.getMethod().hasName("put") or ma.getMethod().hasName("setProperty")) and + ma.getMethod().hasName(["put", "setProperty"]) and ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = fieldValue and ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue } +/** + * Holds if `ma` sets attribute name `fieldName` to `envValue` in some `Hashtable`. + */ +bindingset[fieldName, envValue] +predicate hasFieldNameEnv(MethodAccess ma, string fieldName, string envValue) { + // environment.put(Context.SECURITY_AUTHENTICATION, "simple") + ma.getMethod().getDeclaringType().getAnAncestor() instanceof TypeHashtable and + ma.getMethod().hasName(["put", "setProperty"]) and + exists(Field f | + ma.getArgument(0) = f.getAnAccess() and + f.hasName(fieldName) and + f.getDeclaringType() instanceof TypeNamingContext + ) and + ma.getArgument(1).(CompileTimeConstantExpr).getStringValue() = envValue +} + /** * Holds if `ma` sets `java.naming.security.authentication` (also known as `Context.SECURITY_AUTHENTICATION`) to `simple` in some `Hashtable`. */ predicate isBasicAuthEnv(MethodAccess ma) { - hasEnvWithValue(ma, "java.naming.security.authentication", "simple") + hasFieldValueEnv(ma, "java.naming.security.authentication", "simple") or + hasFieldNameEnv(ma, "SECURITY_AUTHENTICATION", "simple") } /** * Holds if `ma` sets `java.naming.security.protocol` (also known as `Context.SECURITY_PROTOCOL`) to `ssl` in some `Hashtable`. */ -predicate isSSLEnv(MethodAccess ma) { hasEnvWithValue(ma, "java.naming.security.protocol", "ssl") } +predicate isSSLEnv(MethodAccess ma) { + hasFieldValueEnv(ma, "java.naming.security.protocol", "ssl") or + hasFieldNameEnv(ma, "SECURITY_PROTOCOL", "ssl") +} /** * A taint-tracking configuration for `ldap://` URL in LDAP authentication. @@ -141,12 +162,12 @@ class InsecureUrlFlowConfig extends TaintTracking::Configuration { /** * A taint-tracking configuration for `simple` basic-authentication in LDAP configuration. */ -class BasicAuthFlowConfig extends TaintTracking::Configuration { +class BasicAuthFlowConfig extends DataFlow::Configuration { BasicAuthFlowConfig() { this = "InsecureLdapAuth:BasicAuthFlowConfig" } /** Source of `simple` configuration. */ override predicate isSource(DataFlow::Node src) { - src.asExpr().(CompileTimeConstantExpr).getStringValue() = "simple" + exists(MethodAccess ma | isBasicAuthEnv(ma) and ma.getQualifier() = src.asExpr()) } /** Sink of directory context creation. */ @@ -156,26 +177,17 @@ class BasicAuthFlowConfig extends TaintTracking::Configuration { sink.asExpr() = cc.getArgument(0) ) } - - /** Method call of `env.put()`. */ - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(MethodAccess ma | - pred.asExpr() = ma.getArgument(1) and - isBasicAuthEnv(ma) and - succ.asExpr() = ma.getQualifier() - ) - } } /** * A taint-tracking configuration for `ssl` configuration in LDAP authentication. */ -class SSLFlowConfig extends TaintTracking::Configuration { +class SSLFlowConfig extends DataFlow::Configuration { SSLFlowConfig() { this = "InsecureLdapAuth:SSLFlowConfig" } /** Source of `ssl` configuration. */ override predicate isSource(DataFlow::Node src) { - src.asExpr().(CompileTimeConstantExpr).getStringValue() = "ssl" + exists(MethodAccess ma | isSSLEnv(ma) and ma.getQualifier() = src.asExpr()) } /** Sink of directory context creation. */ @@ -185,28 +197,12 @@ class SSLFlowConfig extends TaintTracking::Configuration { sink.asExpr() = cc.getArgument(0) ) } - - /** Method call of `env.put()`. */ - override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(MethodAccess ma | - pred.asExpr() = ma.getArgument(1) and - isSSLEnv(ma) and - succ.asExpr() = ma.getQualifier() - ) - } } -from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureUrlFlowConfig config, VarAccess va +from DataFlow::PathNode source, DataFlow::PathNode sink, InsecureUrlFlowConfig config where config.hasFlowPath(source, sink) and - sink.getNode().asExpr() = va and - exists(BasicAuthFlowConfig bc, DataFlow::PathNode source2, DataFlow::PathNode sink2 | - bc.hasFlowPath(source2, sink2) and - sink2.getNode().asExpr() = va - ) and - not exists(SSLFlowConfig sc, DataFlow::PathNode source3, DataFlow::PathNode sink3 | - sc.hasFlowPath(source3, sink3) and - sink3.getNode().asExpr() = va - ) + exists(BasicAuthFlowConfig bc | bc.hasFlowTo(sink.getNode())) and + not exists(SSLFlowConfig sc | sc.hasFlowTo(sink.getNode())) select sink.getNode(), source, sink, "Insecure LDAP authentication from $@.", source.getNode(), "LDAP connection string" diff --git a/java/ql/src/semmle/code/java/frameworks/Networking.qll b/java/ql/src/semmle/code/java/frameworks/Networking.qll index 997b8075403..cad948ed2f4 100644 --- a/java/ql/src/semmle/code/java/frameworks/Networking.qll +++ b/java/ql/src/semmle/code/java/frameworks/Networking.qll @@ -132,6 +132,7 @@ class UrlOpenConnectionMethod extends Method { /** * A string matching private host names of IPv4 and IPv6, which only matches the host portion therefore checking for port is not necessary. + * Several examples are localhost, reserved IPv4 IP addresses including 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses including [0:0:0:0:0:0:0:1] and [::1] */ class PrivateHostName extends string { bindingset[this] From e4c3544a3f2706625f4c961a38c5d9c8700486e1 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Tue, 2 Feb 2021 21:59:33 +0100 Subject: [PATCH 080/429] Python: Add support for `from foo.bar import baz` This turned out to be fairly simple. Given an import such as ```python from foo.bar.baz import quux ``` we create an API-graph node for each valid dotted prefix of `foo.bar.baz`, i.e. `foo`, `foo.bar`, and `foo.bar.baz`. For these, we then insert nodes in the API graph, such that `foo` steps to `foo.bar` along an edge labeled `bar`, etc. Finally, we only allow undotted names to hang off of the API-graph root. Thus, `foo` will have a `moduleImport` edge off of the root, and a `getMember` edge for `bar` (which in turn has a `getMember` edge for `baz`). Relative imports are explicitly ignored. Finally, this commit also adds inline tests for a variety of ways of importing modules, including a copy of the "import-helper" tests (with a few modifications to allow a single annotation per line, as these get rather long quickly!). --- python/ql/src/semmle/python/ApiGraphs.qll | 56 +++++++++++++++++-- .../dataflow/ApiGraphs/mypkg/__init__.py | 1 + .../dataflow/ApiGraphs/mypkg/bar.py | 1 + .../dataflow/ApiGraphs/mypkg/foo.py | 1 + .../experimental/dataflow/ApiGraphs/options | 1 + .../experimental/dataflow/ApiGraphs/test.py | 34 +++++++++++ .../experimental/dataflow/ApiGraphs/test1.py | 6 ++ .../experimental/dataflow/ApiGraphs/test2.py | 4 ++ .../experimental/dataflow/ApiGraphs/test3.py | 4 ++ .../experimental/dataflow/ApiGraphs/test4.py | 4 ++ .../experimental/dataflow/ApiGraphs/test5.py | 10 ++++ .../experimental/dataflow/ApiGraphs/test6.py | 6 ++ .../experimental/dataflow/ApiGraphs/test7.py | 10 ++++ .../dataflow/ApiGraphs/test_deep.py | 4 ++ .../dataflow/ApiGraphs/use.expected | 0 .../experimental/dataflow/ApiGraphs/use.ql | 30 ++++++++++ 16 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/mypkg/__init__.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/mypkg/bar.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/mypkg/foo.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/options create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test1.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test2.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test3.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test4.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test5.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test6.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test7.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/test_deep.py create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/use.expected create mode 100644 python/ql/test/experimental/dataflow/ApiGraphs/use.ql diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 2dc62ed30a6..2c1ff3b6cf7 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -230,14 +230,52 @@ module API { /** The root of the API graph. */ MkRoot() or /** An abstract representative for imports of the module called `name`. */ - MkModuleImport(string name) { imports(_, name) } or + MkModuleImport(string name) { + imports(_, name) or name = any(ImportExpr e | not e.isRelative()).getAnImportedModuleName() + } or /** A use of an API member at the node `nd`. */ MkUse(DataFlow::Node nd) { use(_, _, nd) } class TUse = MkModuleImport or MkUse; + /** + * Holds if the dotted module name `sub` refers to the `member` member of `base`. + * + * For instance, `prefix_member("foo.bar", "baz", "foo.bar.baz")` would hold. + */ + private predicate prefix_member(TApiNode base, string member, TApiNode sub) { + exists(string base_str, string sub_str | + base = MkModuleImport(base_str) and + sub = MkModuleImport(sub_str) + | + base_str + "." + member = sub_str and + not member.matches("%.%") + ) + } + /** Holds if `imp` is an import of a module named `name` */ - private predicate imports(DataFlow::Node imp, string name) { imp = DataFlow::importNode(name) } + private predicate imports(DataFlow::Node import_node, string name) { + exists(Variable var, Import imp, Alias alias | + alias = imp.getAName() and + alias.getAsname() = var.getAStore() and + ( + name = alias.getValue().(ImportMember).getImportedModuleName() + or + name = alias.getValue().(ImportExpr).getImportedModuleName() and + not alias.getValue().(ImportExpr).isRelative() + ) and + import_node.asExpr() = alias.getValue() + ) + or + exists(ImportExpr imp_expr | + not imp_expr.isRelative() and + imp_expr.getName() = name and + import_node.asCfgNode().getNode() = imp_expr and + // in `import foo.bar` we DON'T want to give a result for `importNode("foo.bar")`, + // only for `importNode("foo")`. We exclude those cases with the following clause. + not exists(Import imp | imp.getAName().getValue() = imp_expr) + ) + } /** * Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled @@ -248,9 +286,11 @@ module API { exists(DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode pred | use(base, src) and pred = trackUseNode(src) | + // Reading an attribute on a node that is a use of `base`: lbl = Label::memberFromRef(ref) and ref = pred.getAnAttributeRead() or + // Calling a node that is a use of `base` lbl = Label::return() and ref = pred.getAnInvocation() ) @@ -263,7 +303,7 @@ module API { predicate use(TApiNode nd, DataFlow::Node ref) { exists(string name | nd = MkModuleImport(name) and - ref = DataFlow::importNode(name) + imports(ref, name) ) or nd = MkUse(ref) @@ -310,7 +350,15 @@ module API { pred = MkRoot() and lbl = Label::mod(m) | - succ = MkModuleImport(m) + succ = MkModuleImport(m) and + // Only allow undotted names to count as base modules. + not m.matches("%.%") + ) + or + /* Step from the dotted module name `foo.bar` to `foo.bar.baz` along an edge labeled `baz` */ + exists(string member | + prefix_member(pred, member, succ) and + lbl = Label::member(member) ) or /* Every node that is a use of an API component is itself added to the API graph. */ diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/__init__.py b/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/__init__.py new file mode 100644 index 00000000000..c84a9b135a3 --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/__init__.py @@ -0,0 +1 @@ +foo = 42 diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/bar.py b/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/bar.py new file mode 100644 index 00000000000..2ae28399f5f --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/bar.py @@ -0,0 +1 @@ +pass diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/foo.py b/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/foo.py new file mode 100644 index 00000000000..2ae28399f5f --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/mypkg/foo.py @@ -0,0 +1 @@ +pass diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/options b/python/ql/test/experimental/dataflow/ApiGraphs/options new file mode 100644 index 00000000000..1099600818b --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/options @@ -0,0 +1 @@ +semmle-extractor-options: --lang=3 \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py new file mode 100644 index 00000000000..c361e3a169f --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -0,0 +1,34 @@ +import a1 #$ use=moduleImport("a1") + +x = a1.blah1 #$ use=moduleImport("a1").getMember("blah1") + +import a2 as m2 #$ use=moduleImport("a2") + +x2 = m2.blah2 #$ use=moduleImport("a2").getMember("blah2") + +import a3.b3 as m3 #$ use=moduleImport("a3").getMember("b3") + +x3 = m3.blah3 #$ use=moduleImport("a3").getMember("b3").getMember("blah3") + +from a4.b4 import c4 as m4 #$ use=moduleImport("a4").getMember("b4").getMember("c4") + +x4 = m4.blah4 #$ use=moduleImport("a4").getMember("b4").getMember("c4").getMember("blah4") + +import a.b.c.d #$ use=moduleImport("a") + +ab = a.b #$ use=moduleImport("a").getMember("b") + +abc = ab.c #$ use=moduleImport("a").getMember("b").getMember("c") + +abcd = abc.d #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d") + +x5 = abcd() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getReturn() + +y5 = x5.method() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getReturn().getMember("method").getReturn() + + +# Relative imports. These are ignored + +from .foo import bar + +from ..foobar import baz \ No newline at end of file diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test1.py b/python/ql/test/experimental/dataflow/ApiGraphs/test1.py new file mode 100644 index 00000000000..847abda7749 --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test1.py @@ -0,0 +1,6 @@ +import mypkg #$ use=moduleImport("mypkg") +print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // 42 +try: + print(mypkg.bar) #$ use=moduleImport("mypkg").getMember("bar") +except AttributeError as e: + print(e) # module 'mypkg' has no attribute 'bar' diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test2.py b/python/ql/test/experimental/dataflow/ApiGraphs/test2.py new file mode 100644 index 00000000000..dce67f0b034 --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test2.py @@ -0,0 +1,4 @@ +from mypkg import foo #$ use=moduleImport("mypkg").getMember("foo") +from mypkg import bar #$ use=moduleImport("mypkg").getMember("bar") +print(foo) #$ use=moduleImport("mypkg").getMember("foo") +print(bar) #$ use=moduleImport("mypkg").getMember("bar") diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test3.py b/python/ql/test/experimental/dataflow/ApiGraphs/test3.py new file mode 100644 index 00000000000..83ff25cc402 --- /dev/null +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test3.py @@ -0,0 +1,4 @@ +import mypkg.foo #$ use=moduleImport("mypkg") +import mypkg.bar #$ use=moduleImport("mypkg") +print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // Date: Wed, 3 Feb 2021 08:49:37 +0100 Subject: [PATCH 081/429] Revert "Merge pull request #4784 from MathiasVP/mathiasvp/reverse-read-take-3" This reverts commit 1b3d69d617a46b9c966b886e9941bd6cce9fcc9b, reversing changes made to 527c41520e2d7ee8ca941d254545d0cc5300b608. --- .../ir/dataflow/internal/DataFlowPrivate.qll | 342 ++++++------- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 391 ++++----------- .../dataflow-ir-consistency.expected | 65 ++- .../dataflow/dataflow-tests/test.cpp | 2 +- .../dataflow/fields/aliasing.cpp | 28 -- .../dataflow/fields/by_reference.cpp | 12 +- .../fields/dataflow-consistency.expected | 8 - .../fields/dataflow-ir-consistency.expected | 200 +++++--- .../dataflow/fields/ir-path-flow.expected | 468 +++++------------- .../fields/partial-definition-diff.expected | 263 ++++++---- .../fields/partial-definition-ir.expected | 266 ---------- .../fields/partial-definition.expected | 17 - .../dataflow/fields/path-flow.expected | 55 -- .../library-tests/dataflow/fields/simple.cpp | 12 - .../dataflow-ir-consistency.expected | 194 ++++---- .../TaintedAllocationSize.expected | 24 +- .../ArithmeticUncontrolled.expected | 30 +- 17 files changed, 885 insertions(+), 1492 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 68b31a732f4..762ce8d47b4 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -2,7 +2,6 @@ private import cpp private import DataFlowUtil private import semmle.code.cpp.ir.IR private import DataFlowDispatch -private import semmle.code.cpp.models.interfaces.DataFlow /** * A data flow node that occurs as the argument of a call and is passed as-is @@ -210,13 +209,6 @@ private class FieldContent extends Content, TFieldContent { predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit } Field getAField() { result = getAField(c, startBit, endBit) } - - pragma[noinline] - Field getADirectField() { - c = result.getDeclaringType() and - this.getAField() = result and - this.hasOffset(c, _, _) - } } private class CollectionContent extends Content, TCollectionContent { @@ -229,101 +221,69 @@ private class ArrayContent extends Content, TArrayContent { override string toString() { result = "array content" } } -/** - * A store step from the value of a `StoreInstruction` to the "innermost" field of the destination. - * This predicate only holds when there is no `ChiInsturction` that merges the result of the - * `StoreInstruction` into a larger memory. - */ -private predicate instrToFieldNodeStoreStepNoChi( - Node node1, FieldContent f, PartialDefinitionNode node2 -) { - exists(StoreInstruction store, PartialFieldDefinition pd | - pd = node2.getPartialDefinition() and - not exists(ChiInstruction chi | chi.getPartial() = store) and - pd.getPreUpdateNode() = GetFieldNode::fromInstruction(store.getDestinationAddress()) and +private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) { + exists(StoreInstruction store, Class c | + store = node2.asInstruction() and store.getSourceValueOperand() = node1.asOperand() and - f.getADirectField() = pd.getPreUpdateNode().getField() + getWrittenField(store, f.(FieldContent).getAField(), c) and + f.hasOffset(c, _, _) ) } -/** - * A store step from a `StoreInstruction` to the "innermost" field - * of the destination. This predicate only holds when there exists a `ChiInstruction` that merges the - * result of the `StoreInstruction` into a larger memory. - */ -private predicate instrToFieldNodeStoreStepChi( - Node node1, FieldContent f, PartialDefinitionNode node2 -) { - exists( - ChiPartialOperand operand, StoreInstruction store, ChiInstruction chi, PartialFieldDefinition pd - | - pd = node2.getPartialDefinition() and - not chi.isResultConflated() and - node1.asOperand() = operand and +private FieldAddressInstruction getFieldInstruction(Instruction instr) { + result = instr or + result = instr.(CopyValueInstruction).getUnary() +} + +pragma[noinline] +private predicate getWrittenField(Instruction instr, Field f, Class c) { + exists(FieldAddressInstruction fa | + fa = + getFieldInstruction([ + instr.(StoreInstruction).getDestinationAddress(), + instr.(WriteSideEffectInstruction).getDestinationAddress() + ]) and + f = fa.getField() and + c = f.getDeclaringType() + ) +} + +private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) { + exists(ChiPartialOperand operand, ChiInstruction chi | chi.getPartialOperand() = operand and - store = operand.getDef() and - pd.getPreUpdateNode() = GetFieldNode::fromInstruction(store.getDestinationAddress()) and - f.getADirectField() = pd.getPreUpdateNode().getField() - ) -} - -private predicate callableWithoutDefinitionStoreStep( - Node node1, FieldContent f, PartialDefinitionNode node2 -) { - exists( - WriteSideEffectInstruction write, ChiInstruction chi, PartialFieldDefinition pd, - Function callable, CallInstruction call - | - chi.getPartial() = write and - not chi.isResultConflated() and - pd = node2.getPartialDefinition() and - pd.getPreUpdateNode() = GetFieldNode::fromInstruction(write.getDestinationAddress()) and - f.getADirectField() = pd.getPreUpdateNode().getField() and - call = write.getPrimaryInstruction() and - callable = call.getStaticCallTarget() and - not callable.hasDefinition() - | - exists(OutParameterDeref out | out.getIndex() = write.getIndex() | - callable.(DataFlowFunction).hasDataFlow(_, out) and - node1.asInstruction() = write - ) - or - // Ideally we shouldn't need to do a store step from a read side effect, but if we don't have a - // model for the callee there might not be flow to the write side effect (since the callee has no - // definition). This case ensures that we propagate dataflow when a field is passed into a - // function that has a write side effect, even though the write side effect doesn't have incoming - // flow. - not callable instanceof DataFlowFunction and - exists(ReadSideEffectInstruction read | call = read.getPrimaryInstruction() | - node1.asInstruction() = read.getSideEffectOperand().getAnyDef() + node1.asOperand() = operand and + node2.asInstruction() = chi and + exists(Class c | + c = chi.getResultType() and + exists(int startBit, int endBit | + chi.getUpdatedInterval(startBit, endBit) and + f.hasOffset(c, startBit, endBit) + ) + or + getWrittenField(operand.getDef(), f.getAField(), c) and + f.hasOffset(c, _, _) ) ) } -/** - * A store step from a `StoreInstruction` to the `ChiInstruction` generated from assigning - * to a pointer or array indirection - */ -private predicate arrayStoreStepChi(Node node1, ArrayContent a, PartialDefinitionNode node2) { +private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) { a = TArrayContent() and - exists( - ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store, PartialDefinition pd - | - pd = node2.getPartialDefinition() and + exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store | chi.getPartialOperand() = operand and store = operand.getDef() and node1.asOperand() = operand and // This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode` // and `PointerStoreNode` require it in their characteristic predicates. - pd.getPreUpdateNode().asOperand() = chi.getTotalOperand() - | - // `x[i] = taint()` - // This matches the characteristic predicate in `ArrayStoreNode`. - store.getDestinationAddress() instanceof PointerAddInstruction - or - // `*p = taint()` - // This matches the characteristic predicate in `PointerStoreNode`. - store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + node2.asInstruction() = chi and + ( + // `x[i] = taint()` + // This matches the characteristic predicate in `ArrayStoreNode`. + store.getDestinationAddress() instanceof PointerAddInstruction + or + // `*p = taint()` + // This matches the characteristic predicate in `PointerStoreNode`. + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction + ) ) } @@ -333,10 +293,82 @@ private predicate arrayStoreStepChi(Node node1, ArrayContent a, PartialDefinitio * value of `node1`. */ predicate storeStep(Node node1, Content f, PostUpdateNode node2) { - instrToFieldNodeStoreStepNoChi(node1, f, node2) or - instrToFieldNodeStoreStepChi(node1, f, node2) or + fieldStoreStepNoChi(node1, f, node2) or + fieldStoreStepChi(node1, f, node2) or arrayStoreStepChi(node1, f, node2) or - callableWithoutDefinitionStoreStep(node1, f, node2) + fieldStoreStepAfterArraySuppression(node1, f, node2) +} + +// This predicate pushes the correct `FieldContent` onto the access path when the +// `suppressArrayRead` predicate has popped off an `ArrayContent`. +private predicate fieldStoreStepAfterArraySuppression( + Node node1, FieldContent f, PostUpdateNode node2 +) { + exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c | + not chi.isResultConflated() and + node1.asInstruction() = chi and + node2.asInstruction() = chi and + chi.getPartial() = write and + getWrittenField(write, f.getAField(), c) and + f.hasOffset(c, _, _) + ) +} + +bindingset[result, i] +private int unbindInt(int i) { i <= result and i >= result } + +pragma[noinline] +private predicate getLoadedField(LoadInstruction load, Field f, Class c) { + exists(FieldAddressInstruction fa | + fa = load.getSourceAddress() and + f = fa.getField() and + c = f.getDeclaringType() + ) +} + +/** + * Holds if data can flow from `node1` to `node2` via a read of `f`. + * Thus, `node1` references an object with a field `f` whose value ends up in + * `node2`. + */ +private predicate fieldReadStep(Node node1, FieldContent f, Node node2) { + exists(LoadOperand operand | + node2.asOperand() = operand and + node1.asInstruction() = operand.getAnyDef() and + exists(Class c | + c = operand.getAnyDef().getResultType() and + exists(int startBit, int endBit | + operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and + f.hasOffset(c, startBit, endBit) + ) + or + getLoadedField(operand.getUse(), f.getAField(), c) and + f.hasOffset(c, _, _) + ) + ) +} + +/** + * When a store step happens in a function that looks like an array write such as: + * ```cpp + * void f(int* pa) { + * pa = source(); + * } + * ``` + * it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is + * the case, the `ArrayContent` that was written by the call to `f` should be popped off the access + * path, and a `FieldContent` containing `x` should be pushed instead. + * So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression` + * predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path. + */ +predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) { + a = TArrayContent() and + exists(WriteSideEffectInstruction write, ChiInstruction chi | + node1.asInstruction() = write and + node2.asInstruction() = chi and + chi.getPartial() = write and + getWrittenField(write, _, _) + ) } private class ArrayToPointerConvertInstruction extends ConvertInstruction { @@ -346,96 +378,34 @@ private class ArrayToPointerConvertInstruction extends ConvertInstruction { } } -private class InexactLoadOperand extends LoadOperand { - InexactLoadOperand() { this.isDefinitionInexact() } -} - -/** Get the result type of `i`, if it is a `PointerType`. */ -private PointerType getPointerType(Instruction i) { - // We are done if the type is a pointer type that is not a glvalue - i.getResultLanguageType().hasType(result, false) +private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) { + copy.getUnary() = result and not result instanceof CopyValueInstruction or - // Some instructions produce a glvalue. Recurse past those to get the actual `PointerType`. - result = getPointerType(i.(PointerOffsetInstruction).getLeft()) + result = skipOneCopyValueInstructionRec(copy.getUnary()) } -pragma[noinline] -private predicate deconstructLoad( - LoadInstruction load, InexactLoadOperand loadOperand, Instruction addressInstr -) { - load.getSourceAddress() = addressInstr and - load.getSourceValueOperand() = loadOperand +private Instruction skipCopyValueInstructions(Operand op) { + not result instanceof CopyValueInstruction and result = op.getDef() + or + result = skipOneCopyValueInstructionRec(op.getDef()) } private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and // Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array. - exists(InexactLoadOperand loadOperand, LoadInstruction load, Instruction address | - deconstructLoad(load, loadOperand, address) and - node1.asInstruction() = loadOperand.getAnyDef() and - not node1.asInstruction().isResultConflated() and - loadOperand = node2.asOperand() and - // Ensure that the load is actually loading from an array or a pointer. - getPointerType(address).getBaseType() = load.getResultType() - ) -} - -/** Step from the value loaded by a `LoadInstruction` to the "outermost" loaded field. */ -private predicate instrToFieldNodeReadStep(FieldNode node1, FieldContent f, Node node2) { - ( - node1.getNextNode() = node2 - or - not exists(node1.getNextNode()) and - ( - exists(LoadInstruction load | - node2.asInstruction() = load and - node1 = GetFieldNode::fromInstruction(load.getSourceAddress()) - ) - or - exists(ReadSideEffectInstruction read | - node2.asOperand() = read.getSideEffectOperand() and - node1 = GetFieldNode::fromInstruction(read.getArgumentDef()) - ) - ) - ) and - f.getADirectField() = node1.getField() -} - -bindingset[result, i] -private int unbindInt(int i) { i <= result and i >= result } - -pragma[noinline] -private FieldNode getFieldNodeFromLoadOperand(LoadOperand loadOperand) { - result = GetFieldNode::fromOperand(loadOperand.getAddressOperand()) -} - -/** - * Sometimes there's no explicit field dereference. In such cases we use the IR alias analysis to - * determine the offset being, and deduce the field from this information. - */ -private predicate aliasedReadStep(Node node1, FieldContent f, Node node2) { - exists(LoadOperand operand, Class c, int startBit, int endBit | - // Ensure that we don't already catch this store step using a `FieldNode`. - not instrToFieldNodeReadStep(getFieldNodeFromLoadOperand(operand), f, _) and + exists(LoadOperand operand, Instruction address | + operand.isDefinitionInexact() and node1.asInstruction() = operand.getAnyDef() and - node2.asOperand() = operand and - not node1.asInstruction().isResultConflated() and - c = operand.getAnyDef().getResultType() and - f.hasOffset(c, startBit, endBit) and - operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) + operand = node2.asOperand() and + address = skipCopyValueInstructions(operand.getAddressOperand()) and + ( + address instanceof LoadInstruction or + address instanceof ArrayToPointerConvertInstruction or + address instanceof PointerOffsetInstruction + ) ) } -/** Get the result type of an `Instruction` i, if it is a `ReferenceType`. */ -private ReferenceType getReferenceType(Instruction i) { - i.getResultLanguageType().hasType(result, false) -} - -pragma[noinline] -Type getResultTypeOfSourceValue(CopyValueInstruction copy) { - result = copy.getSourceValue().getResultType() -} - /** * In cases such as: * ```cpp @@ -447,25 +417,21 @@ Type getResultTypeOfSourceValue(CopyValueInstruction copy) { * f(&x); * use(x); * ``` - * the store to `*pa` in `f` will push `ArrayContent` onto the access path. The `innerRead` predicate - * pops the `ArrayContent` off the access path when a value-to-pointer or value-to-reference conversion - * happens on the argument that is ends up as the target of such a store. + * the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition + * is a `WriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`) + * from the access path. */ -private predicate innerReadStep(Node node1, Content a, Node node2) { +private predicate exactReadStep(Node node1, ArrayContent a, Node node2) { a = TArrayContent() and - exists(WriteSideEffectInstruction write, CallInstruction call, CopyValueInstruction copyValue | - write.getPrimaryInstruction() = call and + exists(WriteSideEffectInstruction write, ChiInstruction chi | + not chi.isResultConflated() and + chi.getPartial() = write and node1.asInstruction() = write and - ( - not exists(ChiInstruction chi | chi.getPartial() = write) - or - exists(ChiInstruction chi | chi.getPartial() = write and not chi.isResultConflated()) - ) and - node2.asInstruction() = write and - copyValue = call.getArgument(write.getIndex()) and - // Check that `copyValue` is actually doing a T to a T* conversion. - [getPointerType(copyValue).getBaseType(), getReferenceType(copyValue).getBaseType()].stripType() = - getResultTypeOfSourceValue(copyValue).stripType() + node2.asInstruction() = chi and + // To distinquish this case from the `arrayReadStep` case we require that the entire variable was + // overwritten by the `WriteSideEffectInstruction` (i.e., there is a load that reads the + // entire variable). + exists(LoadInstruction load | load.getSourceValue() = chi) ) } @@ -475,10 +441,10 @@ private predicate innerReadStep(Node node1, Content a, Node node2) { * `node2`. */ predicate readStep(Node node1, Content f, Node node2) { - aliasedReadStep(node1, f, node2) or + fieldReadStep(node1, f, node2) or arrayReadStep(node1, f, node2) or - instrToFieldNodeReadStep(node1, f, node2) or - innerReadStep(node1, f, node2) + exactReadStep(node1, f, node2) or + suppressArrayRead(node1, f, node2) } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index aba8e3bceec..b21a0abc20b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -15,11 +15,7 @@ cached private newtype TIRDataFlowNode = TInstructionNode(Instruction i) or TOperandNode(Operand op) or - TVariableNode(Variable var) or - // `FieldNodes` are used as targets of certain `storeStep`s to implement handling of stores to - // nested structs. - TFieldNode(FieldAddressInstruction field) or - TPartialDefinitionNode(PartialDefinition pd) + TVariableNode(Variable var) /** * A node in a data flow graph. @@ -32,22 +28,7 @@ class Node extends TIRDataFlowNode { /** * INTERNAL: Do not use. */ - final Declaration getEnclosingCallable() { - result = unique(Declaration d | d = this.getEnclosingCallableImpl() | d) - } - - final private Declaration getEnclosingCallableImpl() { - result = this.asInstruction().getEnclosingFunction() or - result = this.asOperand().getUse().getEnclosingFunction() or - // When flow crosses from one _enclosing callable_ to another, the - // interprocedural data-flow library discards call contexts and inserts a - // node in the big-step relation used for human-readable path explanations. - // Therefore we want a distinct enclosing callable for each `VariableNode`, - // and that can be the `Variable` itself. - result = this.asVariable() or - result = this.(FieldNode).getFieldInstruction().getEnclosingFunction() or - result = this.(PartialDefinitionNode).getPreUpdateNode().getFunction() - } + Declaration getEnclosingCallable() { none() } // overridden in subclasses /** Gets the function to which this node belongs, if any. */ Function getFunction() { none() } // overridden in subclasses @@ -152,6 +133,8 @@ class InstructionNode extends Node, TInstructionNode { /** Gets the instruction corresponding to this node. */ Instruction getInstruction() { result = instr } + override Declaration getEnclosingCallable() { result = this.getFunction() } + override Function getFunction() { result = instr.getEnclosingFunction() } override IRType getType() { result = instr.getResultIRType() } @@ -176,6 +159,8 @@ class OperandNode extends Node, TOperandNode { /** Gets the operand corresponding to this node. */ Operand getOperand() { result = op } + override Declaration getEnclosingCallable() { result = this.getFunction() } + override Function getFunction() { result = op.getUse().getEnclosingFunction() } override IRType getType() { result = op.getIRType() } @@ -185,139 +170,6 @@ class OperandNode extends Node, TOperandNode { override string toString() { result = this.getOperand().toString() } } -/** - * INTERNAL: do not use. Encapsulates the details of getting a `FieldNode` from - * an `Instruction` or an `Operand`. - */ -module GetFieldNode { - /** An abstract class that defines conversion-like instructions. */ - abstract private class SkippableInstruction extends Instruction { - abstract Instruction getSourceInstruction(); - } - - /** - * Gets the instruction that is propaged through a non-empty sequence of conversion-like instructions. - */ - private Instruction skipSkippableInstructionsRec(SkippableInstruction skip) { - result = skip.getSourceInstruction() and not result instanceof SkippableInstruction - or - result = skipSkippableInstructionsRec(skip.getSourceInstruction()) - } - - /** - * Gets the instruction that is propagated through a (possibly empty) sequence of conversion-like - * instructions. - */ - private Instruction skipSkippableInstructions(Instruction instr) { - result = instr and not result instanceof SkippableInstruction - or - result = skipSkippableInstructionsRec(instr) - } - - private class SkippableCopyValueInstruction extends SkippableInstruction, CopyValueInstruction { - override Instruction getSourceInstruction() { result = this.getSourceValue() } - } - - private class SkippableConvertInstruction extends SkippableInstruction, ConvertInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } - } - - private class SkippableCheckedConvertInstruction extends SkippableInstruction, - CheckedConvertOrNullInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } - } - - private class SkippableInheritanceConversionInstruction extends SkippableInstruction, - InheritanceConversionInstruction { - override Instruction getSourceInstruction() { result = this.getUnary() } - } - - /** - * INTERNAL: do not use. Gets the `FieldNode` corresponding to `instr`, if - * `instr` is an instruction that propagates an address of a `FieldAddressInstruction`. - */ - FieldNode fromInstruction(Instruction instr) { - result.getFieldInstruction() = skipSkippableInstructions(instr) - } - - /** - * INTERNAL: do not use. Gets the `FieldNode` corresponding to `op`, if the definition - * of `op` is an instruction that propagates an address of a `FieldAddressInstruction`. - */ - FieldNode fromOperand(Operand op) { result = fromInstruction(op.getDef()) } -} - -/** - * INTERNAL: do not use. A `FieldNode` represents the state of a field before any partial definitions - * of the field. For instance, in the snippet: - * ```cpp - * struct A { struct B { int c; } b; }; - * // ... - * A a; - * f(a.b.c); - * ``` - * there are two `FieldNode`s: one corresponding to `c`, and one corresponding to `b`. Similarly, - * in `a.b.c = x` there are two `FieldNode`s: one for `c` and one for `b`. - */ -class FieldNode extends Node, TFieldNode { - FieldAddressInstruction field; - - FieldNode() { this = TFieldNode(field) } - - /** Gets the `Field` of this `FieldNode`. */ - Field getField() { result = getFieldInstruction().getField() } - - /** Gets the `FieldAddressInstruction` of this `FieldNode`. */ - FieldAddressInstruction getFieldInstruction() { result = field } - - /** - * Gets the `FieldNode` corresponding to the parent field of this `FieldNode`, if any. - * - * For example, if `f` is the `FieldNode` for `c` in the expression `a.b.c`, then `f.getObjectNode()` - * gives the `FieldNode` of `b`, and `f.getObjectNode().getObjectNode()` has no result as `a` is - * not a field. - */ - FieldNode getObjectNode() { result = GetFieldNode::fromInstruction(field.getObjectAddress()) } - - /** - * Gets the `FieldNode` that has this `FieldNode` as parent, if any. - * - * For example, if `f` is the `FieldNode` corresponding to `b` in `a.b.c`, then `f.getNextNode()` - * gives the `FieldNode` corresponding to `c`, and `f.getNextNode().getNextNode()`. - */ - FieldNode getNextNode() { result.getObjectNode() = this } - - /** Gets the class where the field of this node is declared. */ - Class getDeclaringType() { result = getField().getDeclaringType() } - - override Function getFunction() { result = field.getEnclosingFunction() } - - override IRType getType() { result = field.getResultIRType() } - - override Location getLocation() { result = field.getLocation() } - - override string toString() { result = this.getField().toString() } -} - -/** - * INTERNAL: do not use. A partial definition of a `FieldNode`. - */ -class PartialFieldDefinition extends FieldNode, PartialDefinition { - /** - * The pre-update node of a partial definition of a `FieldNode` is the `FieldNode` itself. This ensures - * that the data flow library's reverse read mechanism builds up the correct access path for nested - * fields. - * For instance, in `a.b.c = x` there is a partial definition for `c` (let's call it `post[c]`) and a - * partial definition for `b` (let's call it `post[b]`), and there is a read step from `b` to `c` - * (using `instrToFieldNodeReadStep`), so there is a store step from `post[c]` to `post[b]`. - */ - override FieldNode getPreUpdateNode() { result = this } - - override Expr getDefinedExpr() { - result = this.getFieldInstruction().getObjectAddress().getUnconvertedResultExpression() - } -} - /** * An expression, viewed as a node in a data flow graph. */ @@ -455,26 +307,11 @@ deprecated class UninitializedNode extends Node { * This class exists to match the interface used by Java. There are currently no non-abstract * classes that extend it. When we implement field flow, we can revisit this. */ -abstract class PostUpdateNode extends Node { +abstract class PostUpdateNode extends InstructionNode { /** * Gets the node before the state update. */ abstract Node getPreUpdateNode(); - - override Function getFunction() { result = getPreUpdateNode().getFunction() } - - override IRType getType() { result = getPreUpdateNode().getType() } - - override Location getLocation() { result = getPreUpdateNode().getLocation() } -} - -/** INTERNAL: do not use. A partial definition of a node. */ -abstract class PartialDefinition extends Node { - /** Gets the node before the state update. */ - abstract Node getPreUpdateNode(); - - /** Gets the expression that is partially defined by this node. */ - abstract Expr getDefinedExpr(); } /** @@ -490,40 +327,112 @@ abstract class PartialDefinition extends Node { * setY(&x); // a partial definition of the object `x`. * ``` */ -class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode { - PartialDefinition pd; +abstract private class PartialDefinitionNode extends PostUpdateNode { + abstract Expr getDefinedExpr(); +} - PartialDefinitionNode() { this = TPartialDefinitionNode(pd) } +private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + StoreInstruction store; - /** Gets the expression that is partially defined by this node, if any. */ - Expr getDefinedExpr() { result = pd.getDefinedExpr() } + ExplicitFieldStoreQualifierNode() { + not instr.isResultConflated() and + instr.getPartial() = store and + ( + instr.getUpdatedInterval(_, _) or + store.getDestinationAddress() instanceof FieldAddressInstruction + ) + } - override Node getPreUpdateNode() { result = pd.getPreUpdateNode() } + // By using an operand as the result of this predicate we avoid the dataflow inconsistency errors + // caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause + // a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node + // into a big step. + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } - /** Gets the `PartialDefinition` associated with this node. */ - PartialDefinition getPartialDefinition() { result = pd } + override Expr getDefinedExpr() { + result = + store + .getDestinationAddress() + .(FieldAddressInstruction) + .getObjectAddress() + .getUnconvertedResultExpression() + } +} - override string toString() { result = getPreUpdateNode().toString() + " [post update]" } +/** + * Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to. + * For instance, an update to a field of a struct containing only one field. For these cases we + * attach the PostUpdateNode to the store instruction. There's no obvious pre update node for this case + * (as the entire memory is updated), so `getPreUpdateNode` is implemented as `none()`. + */ +private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode { + override StoreInstruction instr; + + ExplicitSingleFieldStoreQualifierNode() { + not exists(ChiInstruction chi | chi.getPartial() = instr) and + // Without this condition any store would create a `PostUpdateNode`. + instr.getDestinationAddress() instanceof FieldAddressInstruction + } + + override Node getPreUpdateNode() { none() } + + override Expr getDefinedExpr() { + result = + instr + .getDestinationAddress() + .(FieldAddressInstruction) + .getObjectAddress() + .getUnconvertedResultExpression() + } +} + +private FieldAddressInstruction getFieldInstruction(Instruction instr) { + result = instr or + result = instr.(CopyValueInstruction).getUnary() +} + +/** + * The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert + * an `ArrayContent` to a `FieldContent` when the `WriteSideEffect` instruction stores + * into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion + * is inserted. + */ +private class WriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode { + override ChiInstruction instr; + WriteSideEffectInstruction write; + FieldAddressInstruction field; + + WriteSideEffectFieldStoreQualifierNode() { + not instr.isResultConflated() and + instr.getPartial() = write and + field = getFieldInstruction(write.getDestinationAddress()) + } + + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } + + override Expr getDefinedExpr() { + result = field.getObjectAddress().getUnconvertedResultExpression() + } } /** * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class ArrayStoreNode extends InstructionNode, PartialDefinition { - ChiInstruction chi; +private class ArrayStoreNode extends PartialDefinitionNode { + override ChiInstruction instr; PointerAddInstruction add; ArrayStoreNode() { - chi = this.getInstruction() and - not chi.isResultConflated() and + not instr.isResultConflated() and exists(StoreInstruction store | - chi.getPartial() = store and + instr.getPartial() = store and add = store.getDestinationAddress() ) } - override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() } } @@ -532,24 +441,18 @@ private class ArrayStoreNode extends InstructionNode, PartialDefinition { * The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden * `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`. */ -private class PointerStoreNode extends InstructionNode, PartialDefinition { - ChiInstruction chi; - LoadInstruction load; +private class PointerStoreNode extends PostUpdateNode { + override ChiInstruction instr; PointerStoreNode() { - chi = this.getInstruction() and - not chi.isResultConflated() and + not instr.isResultConflated() and exists(StoreInstruction store | - chi.getPartial() = store and - load = store.getDestinationAddress().(CopyValueInstruction).getUnary() + instr.getPartial() = store and + store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction ) } - override Node getPreUpdateNode() { result.asOperand() = chi.getTotalOperand() } - - override Expr getDefinedExpr() { - result = load.getSourceAddress().getUnconvertedResultExpression() - } + override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() } } /** @@ -562,7 +465,7 @@ private class PointerStoreNode extends InstructionNode, PartialDefinition { * returned. This node will have its `getArgument()` equal to `&x` and its * `getVariableAccess()` equal to `x`. */ -class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode { +class DefinitionByReferenceNode extends InstructionNode { override WriteSideEffectInstruction instr; /** Gets the unconverted argument corresponding to this node. */ @@ -590,22 +493,6 @@ class DefinitionByReferenceNode extends InstructionNode, PostUpdateNode { not exists(instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget()) and result = "output argument" } - - override Function getFunction() { result = instr.getEnclosingFunction() } - - override IRType getType() { result = instr.getResultIRType() } - - override Location getLocation() { result = instr.getLocation() } - - // Make the read side effect's side effect operand the pre update node of this write side effect. - // This ensures that we match up the parameter index of the parameter indirection's modification. - override Node getPreUpdateNode() { - exists(ReadSideEffectInstruction read | - read.getPrimaryInstruction() = instr.getPrimaryInstruction() and - read.getArgumentDef() = instr.getDestinationAddress() and - result.asOperand() = read.getSideEffectOperand() - ) - } } /** @@ -623,6 +510,15 @@ class VariableNode extends Node, TVariableNode { override Function getFunction() { none() } + override Declaration getEnclosingCallable() { + // When flow crosses from one _enclosing callable_ to another, the + // interprocedural data-flow library discards call contexts and inserts a + // node in the big-step relation used for human-readable path explanations. + // Therefore we want a distinct enclosing callable for each `VariableNode`, + // and that can be the `Variable` itself. + result = v + } + override IRType getType() { result.getCanonicalLanguageType().hasUnspecifiedType(v.getType(), _) } override Location getLocation() { result = v.getLocation() } @@ -689,69 +585,6 @@ Node uninitializedNode(LocalVariable v) { none() } */ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFrom, nodeTo) } -private predicate flowOutOfPostUpdate(PartialDefinitionNode nodeFrom, Node nodeTo) { - // flow from the "outermost" field to the `ChiInstruction`, or `StoreInstruction` - // if no `ChiInstruction` exists. - exists(AddressOperand addressOperand, PartialFieldDefinition pd | - pd = nodeFrom.getPartialDefinition() and - not exists(pd.getPreUpdateNode().getObjectNode()) and - pd.getPreUpdateNode().getNextNode*() = GetFieldNode::fromOperand(addressOperand) and - ( - exists(ChiInstruction chi | - nodeTo.asInstruction() = chi and - chi.getPartial().getAnOperand() = addressOperand - ) - or - exists(StoreInstruction store | - not exists(ChiInstruction chi | chi.getPartial() = store) and - nodeTo.asInstruction() = store and - store.getDestinationAddressOperand() = addressOperand - ) - ) - ) - or - // Note: This partial definition cannot be a `PostUpdateFieldNode` since these nodes do not have an - // operand node as their pre update node. - exists(PartialDefinition pd | - pd = nodeFrom.getPartialDefinition() and - nodeTo.asInstruction().(ChiInstruction).getTotalOperand() = pd.getPreUpdateNode().asOperand() - ) -} - -/** - * Gets the `FieldNode` corresponding to the outermost field that is used to compute `address`. - */ -private FieldNode getOutermostFieldNode(Instruction address) { - not exists(result.getObjectNode()) and - result.getNextNode*() = GetFieldNode::fromInstruction(address) -} - -private predicate flowIntoReadNode(Node nodeFrom, FieldNode nodeTo) { - // flow from the memory of a load to the "outermost" field of that load. - exists(LoadInstruction load | - nodeTo = getOutermostFieldNode(load.getSourceAddress()) and - not nodeFrom.asInstruction().isResultConflated() and - nodeFrom.asInstruction() = load.getSourceValueOperand().getAnyDef() - ) - or - // We need this to make stores look like loads for the dataflow library. So when there's a store - // of the form x->y = z we need to make the field node corresponding to y look like it's reading - // from the memory of x. - exists(StoreInstruction store, ChiInstruction chi | - chi.getPartial() = store and - nodeTo = getOutermostFieldNode(store.getDestinationAddress()) and - not nodeFrom.asInstruction().isResultConflated() and - nodeFrom.asInstruction() = chi.getTotal() - ) - or - exists(ReadSideEffectInstruction read, SideEffectOperand sideEffect | - sideEffect = read.getSideEffectOperand() and - not sideEffect.getAnyDef().isResultConflated() and - nodeTo = getOutermostFieldNode(read.getArgumentDef()) and - nodeFrom.asOperand() = sideEffect - ) -} - /** * INTERNAL: do not use. * @@ -765,10 +598,6 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { or // Instruction -> Operand flow simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand()) - or - flowIntoReadNode(nodeFrom, nodeTo) - or - flowOutOfPostUpdate(nodeFrom, nodeTo) } pragma[noinline] diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected index b9f6f717c80..fc6c97aa2a6 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected @@ -26,21 +26,60 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| dispatch.cpp:15:8:15:8 | Top output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:21:8:21:8 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:60:18:60:29 | Bottom output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:61:18:61:29 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| dispatch.cpp:65:10:65:21 | Bottom output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:384:10:384:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:391:10:391:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:400:10:400:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| test.cpp:407:10:407:13 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| test.cpp:384:10:384:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| test.cpp:391:10:391:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| test.cpp:400:10:400:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| test.cpp:407:10:407:13 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| BarrierGuard.cpp:49:3:49:17 | Chi | PostUpdateNode should not be the target of local flow. | +| BarrierGuard.cpp:60:3:60:18 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:28:3:28:34 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:34:22:34:27 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:34:32:34:37 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:39:32:39:37 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:39:42:39:47 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:43:35:43:40 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:43:51:43:51 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:49:25:49:30 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:49:35:49:40 | Chi | PostUpdateNode should not be the target of local flow. | +| clang.cpp:50:3:50:26 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:17:19:17:22 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:17:21:17:21 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:24:2:24:30 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:24:13:24:30 | Chi | PostUpdateNode should not be the target of local flow. | +| example.c:26:2:26:25 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:13:12:13:12 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:13:15:13:15 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. | +| lambdas.cpp:43:3:43:14 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:11:5:11:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:20:5:20:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:22:7:22:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:24:7:24:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:29:5:29:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:31:7:31:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:39:7:39:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:44:5:44:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:46:7:46:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:48:7:48:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:75:5:75:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:83:5:83:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:87:7:87:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:89:7:89:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:94:5:94:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:96:7:96:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:104:7:104:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:109:5:109:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:113:7:113:17 | Chi | PostUpdateNode should not be the target of local flow. | +| ref.cpp:115:7:115:17 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:91:3:91:18 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:115:3:115:17 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:120:3:120:10 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:125:3:125:11 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:359:5:359:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:373:5:373:20 | Chi | PostUpdateNode should not be the target of local flow. | +| test.cpp:465:3:465:15 | Chi | PostUpdateNode should not be the target of local flow. | 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 774ecddeab2..f59552aa2dd 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp @@ -362,7 +362,7 @@ class FlowThroughFields { int f() { sink(field); // tainted or clean? Not sure. taintField(); - sink(field); // $ ast,ir + sink(field); // $ ast MISSING: ir } int calledAfterTaint() { diff --git a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp index 833e85600a6..500bbed53a9 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/aliasing.cpp @@ -204,32 +204,4 @@ void deep_member_field_arrow(S2 *ps2) { void deep_member_field_arrow_different_fields(S2 *ps2) { taint_a_ptr(&ps2->s.m1); sink(ps2->s.m2); -} - -void test_deep_struct_fields() { - S2 s2; - s2.s.m1 = user_input(); - S s = s2.s; - sink(s.m1); // $ ast,ir -} - -void test_deep_struct_fields_no_flow() { - S2 s2; - s2.s.m1 = user_input(); - S s = s2.s; - sink(s.m2); -} - -void test_deep_struct_fields_taint_through_call() { - S2 s2; - taint_a_ptr(&s2.s.m1); - S s = s2.s; - sink(s.m1); // $ ast,ir -} - -void test_deep_struct_fields_taint_through_call_no_flow() { - S2 s2; - taint_a_ptr(&s2.s.m1); - S s = s2.s; - sink(s.m2); } \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp index 46abcd62c07..8e84d39be3b 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/by_reference.cpp @@ -1,4 +1,4 @@ -void sink(void *o); void sink(const char *o); +void sink(void *o); void *user_input(void); struct S { @@ -135,13 +135,3 @@ void test_outer_with_ref(Outer *pouter) { sink(pouter->inner_ptr->a); // $ ast MISSING: ir sink(pouter->a); // $ ast,ir } - -void taint_a_ptr(const char **pa) { - *pa = (char*)user_input(); -} - -void test_const_char_ref() { - const char* s; - taint_a_ptr(&s); - sink(s); // $ ast ir=140:9 ir=140:16 -} \ No newline at end of file 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 500faa38eb1..c6528723d22 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -89,10 +89,6 @@ postWithInFlow | aliasing.cpp:194:21:194:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:200:23:200:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | aliasing.cpp:205:23:205:24 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:211:8:211:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:218:8:218:9 | m1 [post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:225:21:225:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | -| aliasing.cpp:232:21:232:22 | m1 [inner post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:5 | arr [inner post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:6:3:6:8 | access to array [post update] | PostUpdateNode should not be the target of local flow. | | arrays.cpp:15:3:15:10 | * ... [post update] | PostUpdateNode should not be the target of local flow. | @@ -123,9 +119,6 @@ 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. | -| by_reference.cpp:140:3:140:5 | * ... [post update] | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:140:4:140:5 | pa [inner post update] | PostUpdateNode should not be the target of local flow. | -| by_reference.cpp:145:16:145:16 | s [inner 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. | @@ -159,6 +152,5 @@ postWithInFlow | simple.cpp:65:7:65:7 | i [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:83:12:83:13 | f1 [post update] | PostUpdateNode should not be the target of local flow. | | simple.cpp:92:7:92:7 | i [post update] | PostUpdateNode should not be the target of local flow. | -| simple.cpp:104:9:104:9 | i [post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:24:11:24:12 | ab [inner post update] | PostUpdateNode should not be the target of local flow. | | struct_init.c:36:17:36:24 | nestedAB [inner 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 0a03ccef569..63d3b2c0f48 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 @@ -20,71 +20,145 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| A.cpp:9:9:9:9 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:14:9:14:9 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:31:14:31:21 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:38:7:38:8 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:39:7:39:8 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:41:15:41:21 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:47:12:47:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:54:12:54:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:55:12:55:19 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:57:11:57:24 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:57:17:57:23 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:62:13:62:19 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:64:21:64:28 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:71:13:71:19 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:73:25:73:32 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:89:15:89:21 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:99:14:99:21 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:116:12:116:19 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:126:12:126:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:130:12:130:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:142:14:142:20 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:143:25:143:31 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:150:12:150:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:151:12:151:24 | D output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:159:12:159:18 | B output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:160:18:160:60 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:160:32:160:59 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:161:18:161:40 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| A.cpp:162:18:162:40 | MyList output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:7:16:7:35 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:8:16:8:27 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:16:16:16:38 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| B.cpp:17:16:17:27 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| C.cpp:18:12:18:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:29:15:29:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:29:24:29:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:36:15:36:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:36:24:36:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:43:15:43:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:43:24:43:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:50:15:50:41 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:50:24:50:40 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:57:16:57:42 | Box2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| D.cpp:57:25:57:41 | Box1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:22:11:22:17 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:25:7:25:7 | Bar output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:48:9:48:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:49:9:49:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:50:9:50:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| complex.cpp:51:9:51:10 | Outer output argument | PostUpdateNode should have one pre-update node but has 0. | -| conflated.cpp:59:20:59:39 | LinkedList output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:34:11:34:26 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:35:11:35:26 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:36:11:36:37 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructors.cpp:37:11:37:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:34:11:34:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:35:11:35:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:36:11:36:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| simple.cpp:37:11:37:15 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should have one pre-update node but has 0. | +| simple.cpp:92:5:92:22 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| realistic.cpp:54:16:54:47 | memcpy output argument | PostUpdateNode should not be the target of local flow. | -| realistic.cpp:60:16:60:18 | memcpy output argument | PostUpdateNode should not be the target of local flow. | +| A.cpp:25:7:25:17 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:27:22:27:32 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:98:12:98:18 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:100:5:100:13 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:142:7:142:20 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:143:7:143:31 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:183:7:183:20 | Chi | PostUpdateNode should not be the target of local flow. | +| A.cpp:184:7:184:23 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:6:15:6:24 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:15:15:15:27 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:35:7:35:22 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:36:7:36:22 | Chi | PostUpdateNode should not be the target of local flow. | +| B.cpp:46:7:46:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:22:12:22:21 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:5:24:25 | Chi | PostUpdateNode should not be the target of local flow. | +| C.cpp:24:16:24:25 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:9:21:9:28 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:11:29:11:36 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:16:21:16:27 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:18:29:18:35 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:28:15:28:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:35:15:35:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:42:15:42:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:49:15:49:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:56:15:56:24 | Chi | PostUpdateNode should not be the target of local flow. | +| D.cpp:57:5:57:42 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:9:3:9:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:13:3:13:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:17:3:17:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:21:12:21:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:21:15:21:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:22:12:22:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:22:15:22:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:23:12:23:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:23:15:23:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:35:12:35:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:35:15:35:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:37:3:37:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:40:12:40:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:40:15:40:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:42:3:42:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:47:12:47:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:47:15:47:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:49:3:49:25 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:52:12:52:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:52:15:52:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:54:3:54:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:59:12:59:12 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:59:15:59:15 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:60:3:60:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:70:19:70:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:70:22:70:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:72:3:72:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:77:19:77:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:77:22:77:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:79:3:79:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:84:19:84:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:84:22:84:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:86:3:86:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:91:19:91:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:91:22:91:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:92:3:92:23 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:98:3:98:21 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:106:3:106:20 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:111:15:111:19 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:147:15:147:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:175:15:175:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:181:15:181:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:187:15:187:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:194:15:194:22 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:200:15:200:24 | Chi | PostUpdateNode should not be the target of local flow. | +| aliasing.cpp:205:15:205:24 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:5:18:5:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:5:21:5:21 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:6:3:6:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:14:18:14:23 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:14:21:14:21 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:15:3:15:25 | Chi | PostUpdateNode should not be the target of local flow. | +| arrays.cpp:36:3:36:37 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:12:5:12:16 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:16:5:16:19 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:84:3:84:25 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:88:3:88:24 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:92:3:92:20 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:96:3:96:19 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:102:21:102:39 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:104:15:104:22 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:106:21:106:41 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:108:15:108:24 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:122:21:122:38 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:124:15:124:21 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:126:21:126:40 | Chi | PostUpdateNode should not be the target of local flow. | +| by_reference.cpp:128:15:128:23 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:11:22:11:27 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:12:22:12:27 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:14:33:14:33 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:22:11:22:17 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:25:7:25:7 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:42:16:42:16 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:43:16:43:16 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:53:12:53:12 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:54:12:54:12 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:55:12:55:12 | Chi | PostUpdateNode should not be the target of local flow. | +| complex.cpp:56:12:56:12 | Chi | PostUpdateNode should not be the target of local flow. | +| conflated.cpp:45:39:45:42 | Chi | PostUpdateNode should not be the target of local flow. | +| conflated.cpp:53:3:53:27 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | +| constructors.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:9:30:9:44 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:12:49:12:64 | Chi | PostUpdateNode should not be the target of local flow. | +| qualifiers.cpp:13:51:13:65 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:39:12:39:95 | Chi | PostUpdateNode should not be the target of local flow. | +| realistic.cpp:49:9:49:64 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:20:24:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:21:24:21:29 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:23:28:23:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:23:35:23:35 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:65:5:65:22 | Store | PostUpdateNode should not be the target of local flow. | +| simple.cpp:83:9:83:28 | Chi | PostUpdateNode should not be the target of local flow. | +| simple.cpp:92:5:92:22 | Store | PostUpdateNode should not be the target of local flow. | +| struct_init.c:20:20:20:29 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:20:34:20:34 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:27:7:27:16 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:27:21:27:21 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:28:5:28:7 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:36:10:36:24 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:40:20:40:29 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:40:34:40:34 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:42:7:42:16 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:42:21:42:21 | Chi | PostUpdateNode should not be the target of local flow. | +| struct_init.c:43:5:43:7 | Chi | PostUpdateNode should not be the target of local flow. | 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 0f25daa307d..c8b70a74b3a 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 @@ -4,62 +4,50 @@ edges | A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | set output argument [c] | | A.cpp:57:11:57:24 | B output argument [c] | A.cpp:57:28:57:30 | call to get | | A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | B output argument [c] | -| A.cpp:98:12:98:18 | new | A.cpp:100:9:100:9 | a [post update] [a] | -| A.cpp:100:9:100:9 | a [post update] [a] | A.cpp:103:14:103:14 | *c [a] | -| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a [a] | -| A.cpp:107:16:107:16 | a [a] | A.cpp:107:16:107:16 | a | +| A.cpp:98:12:98:18 | new | A.cpp:100:5:100:13 | Chi [a] | +| A.cpp:100:5:100:13 | Chi [a] | A.cpp:103:14:103:14 | *c [a] | +| A.cpp:103:14:103:14 | *c [a] | A.cpp:107:16:107:16 | a | | A.cpp:126:5:126:5 | Chi [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:5:126:5 | set output argument [c] | A.cpp:126:5:126:5 | Chi [c] | -| A.cpp:126:5:126:5 | set output argument [c] | A.cpp:131:8:131:8 | f7 output argument [c] | | A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | set output argument [c] | -| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:132:13:132:13 | c [c] | -| A.cpp:132:13:132:13 | c [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | Chi [c] | A.cpp:132:13:132:13 | c | +| A.cpp:131:8:131:8 | f7 output argument [c] | A.cpp:131:8:131:8 | Chi [c] | | A.cpp:142:7:142:20 | Chi [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:10:142:10 | c [post update] [c] | A.cpp:142:7:142:20 | Chi [c] | -| A.cpp:142:10:142:10 | c [post update] [c] | A.cpp:151:18:151:18 | D output argument [c] | -| A.cpp:142:14:142:20 | new | A.cpp:142:10:142:10 | c [post update] [c] | +| A.cpp:142:14:142:20 | new | A.cpp:142:7:142:20 | Chi [c] | | A.cpp:143:7:143:31 | Chi [b] | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:143:13:143:13 | b [post update] [b] | A.cpp:143:7:143:31 | Chi [b] | -| A.cpp:143:25:143:31 | new | A.cpp:143:13:143:13 | b [post update] [b] | +| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | Chi [b] | | A.cpp:150:12:150:18 | new | A.cpp:151:12:151:24 | D output argument [b] | -| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:152:13:152:13 | b [b] | -| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:154:13:154:13 | c [c] | -| A.cpp:152:13:152:13 | b [b] | A.cpp:152:13:152:13 | b | -| A.cpp:154:13:154:13 | c [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:12:151:24 | Chi [b] | A.cpp:152:13:152:13 | b | +| A.cpp:151:12:151:24 | D output argument [b] | A.cpp:151:12:151:24 | Chi [b] | +| A.cpp:151:18:151:18 | Chi [c] | A.cpp:154:13:154:13 | c | +| A.cpp:151:18:151:18 | D output argument [c] | A.cpp:151:18:151:18 | Chi [c] | | C.cpp:18:12:18:18 | C output argument [s1] | C.cpp:27:8:27:11 | *#this [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | C.cpp:27:8:27:11 | *#this [s3] | -| C.cpp:22:9:22:22 | s1 [post update] [s1] | C.cpp:24:5:24:25 | Chi [s1] | -| C.cpp:22:12:22:21 | new | C.cpp:22:9:22:22 | s1 [post update] [s1] | +| C.cpp:22:12:22:21 | Chi [s1] | C.cpp:24:5:24:25 | Chi [s1] | +| C.cpp:22:12:22:21 | new | C.cpp:22:12:22:21 | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s1] | C.cpp:18:12:18:18 | C output argument [s1] | | C.cpp:24:5:24:25 | Chi [s3] | C.cpp:18:12:18:18 | C output argument [s3] | -| C.cpp:24:11:24:12 | s3 [post update] [s3] | C.cpp:24:5:24:25 | Chi [s3] | -| C.cpp:24:16:24:25 | new | C.cpp:24:11:24:12 | s3 [post update] [s3] | -| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 [s1] | -| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 [s3] | -| C.cpp:29:10:29:11 | s1 [s1] | C.cpp:29:10:29:11 | s1 | -| C.cpp:31:10:31:11 | s3 [s3] | C.cpp:31:10:31:11 | s3 | +| C.cpp:24:16:24:25 | new | C.cpp:24:5:24:25 | Chi [s3] | +| C.cpp:27:8:27:11 | *#this [s1] | C.cpp:29:10:29:11 | s1 | +| C.cpp:27:8:27:11 | *#this [s3] | C.cpp:31:10:31:11 | s3 | | aliasing.cpp:9:3:9:22 | Chi [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | aliasing.cpp:9:3:9:22 | Chi [m1] | -| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | -| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | +| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | Chi [m1] | | aliasing.cpp:13:3:13:21 | Chi [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | aliasing.cpp:13:3:13:21 | Chi [m1] | -| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | -| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | -| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:29:11:29:12 | m1 [m1] | -| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:30:11:30:12 | m1 [m1] | -| aliasing.cpp:29:11:29:12 | m1 [m1] | aliasing.cpp:29:11:29:12 | m1 | -| aliasing.cpp:30:11:30:12 | m1 [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:13:3:13:21 | Chi [m1] | +| aliasing.cpp:25:17:25:19 | Chi [m1] | aliasing.cpp:29:11:29:12 | m1 | +| aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | aliasing.cpp:25:17:25:19 | Chi [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | aliasing.cpp:30:11:30:12 | m1 | +| aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | aliasing.cpp:26:19:26:20 | Chi [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | aliasing.cpp:38:11:38:12 | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | aliasing.cpp:43:13:43:14 | m1 | -| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | aliasing.cpp:62:14:62:15 | m1 [m1] | -| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | -| aliasing.cpp:62:14:62:15 | m1 [m1] | aliasing.cpp:62:14:62:15 | m1 | +| aliasing.cpp:60:3:60:22 | Chi [m1] | aliasing.cpp:61:13:61:14 | Store [m1] | +| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | Chi [m1] | +| aliasing.cpp:61:13:61:14 | Store [m1] | aliasing.cpp:62:14:62:15 | m1 | | aliasing.cpp:79:11:79:20 | call to user_input | aliasing.cpp:80:12:80:13 | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | aliasing.cpp:87:12:87:13 | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | -| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | -| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | +| aliasing.cpp:98:3:98:21 | Chi [m1] | aliasing.cpp:100:14:100:14 | Store [m1] | +| aliasing.cpp:98:10:98:19 | call to user_input | aliasing.cpp:98:3:98:21 | Chi [m1] | | aliasing.cpp:100:14:100:14 | Store [m1] | aliasing.cpp:102:8:102:10 | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | @@ -70,19 +58,7 @@ edges | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | | aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | Chi [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:106:3:106:20 | Chi [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:126:15:126:20 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:131:15:131:16 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:136:15:136:17 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | -| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | +| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:3:106:20 | Chi [array content] | | aliasing.cpp:121:15:121:16 | Chi [array content] | aliasing.cpp:122:8:122:12 | access to array | | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | aliasing.cpp:121:15:121:16 | Chi [array content] | | aliasing.cpp:126:15:126:20 | Chi [array content] | aliasing.cpp:127:8:127:16 | * ... | @@ -95,37 +71,16 @@ edges | aliasing.cpp:158:15:158:20 | taint_a_ptr output argument [array content] | aliasing.cpp:158:15:158:20 | Chi [array content] | | aliasing.cpp:164:15:164:20 | Chi [array content] | aliasing.cpp:165:8:165:16 | access to array | | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | aliasing.cpp:164:15:164:20 | Chi [array content] | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | -| aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | aliasing.cpp:176:11:176:11 | s [s, m1] | -| aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | -| aliasing.cpp:176:11:176:11 | s [s, m1] | aliasing.cpp:176:13:176:14 | m1 [m1] | -| aliasing.cpp:176:13:176:14 | m1 [m1] | aliasing.cpp:176:13:176:14 | m1 | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | -| aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | aliasing.cpp:189:13:189:13 | s [s, m1] | -| aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | -| aliasing.cpp:189:13:189:13 | s [s, m1] | aliasing.cpp:189:15:189:16 | m1 [m1] | -| aliasing.cpp:189:15:189:16 | m1 [m1] | aliasing.cpp:189:15:189:16 | m1 | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | -| aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | aliasing.cpp:201:13:201:13 | s [s, m1] | -| aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | -| aliasing.cpp:201:13:201:13 | s [s, m1] | aliasing.cpp:201:15:201:16 | m1 [m1] | -| aliasing.cpp:201:15:201:16 | m1 [m1] | aliasing.cpp:201:15:201:16 | m1 | -| aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | aliasing.cpp:212:12:212:12 | s [s, m1] | -| aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | -| aliasing.cpp:212:12:212:12 | s [m1] | aliasing.cpp:213:10:213:11 | m1 [m1] | -| aliasing.cpp:212:12:212:12 | s [s, m1] | aliasing.cpp:212:12:212:12 | s [m1] | -| aliasing.cpp:213:10:213:11 | m1 [m1] | aliasing.cpp:213:10:213:11 | m1 | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | -| aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | aliasing.cpp:226:12:226:12 | s [s, m1] | -| aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | aliasing.cpp:227:10:227:11 | m1 [m1] | -| aliasing.cpp:226:12:226:12 | s [s, m1] | aliasing.cpp:226:12:226:12 | s [m1] | -| aliasing.cpp:227:10:227:11 | m1 [m1] | aliasing.cpp:227:10:227:11 | m1 | +| aliasing.cpp:175:15:175:22 | Chi | aliasing.cpp:175:15:175:22 | Chi [m1] | +| aliasing.cpp:175:15:175:22 | Chi [m1] | aliasing.cpp:176:13:176:14 | m1 | +| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | aliasing.cpp:175:15:175:22 | Chi | +| aliasing.cpp:187:15:187:22 | Chi | aliasing.cpp:187:15:187:22 | Chi [m1] | +| aliasing.cpp:187:15:187:22 | Chi [m1] | aliasing.cpp:188:13:188:14 | Store [m1] | +| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | aliasing.cpp:187:15:187:22 | Chi | +| aliasing.cpp:188:13:188:14 | Store [m1] | aliasing.cpp:189:15:189:16 | m1 | +| aliasing.cpp:200:15:200:24 | Chi | aliasing.cpp:200:15:200:24 | Chi [m1] | +| aliasing.cpp:200:15:200:24 | Chi [m1] | aliasing.cpp:201:15:201:16 | m1 | +| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | aliasing.cpp:200:15:200:24 | Chi | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | @@ -141,126 +96,65 @@ edges | by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | nonMemberSetA output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | | by_reference.cpp:84:3:84:25 | Chi [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:84:3:84:25 | Chi [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:10:84:10 | a [post update] [a] | +| by_reference.cpp:84:14:84:23 | call to user_input | by_reference.cpp:84:3:84:25 | Chi [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | | by_reference.cpp:88:3:88:24 | Chi [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:88:3:88:24 | Chi [a] | -| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:9:88:9 | a [post update] [a] | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | -| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:9:88:9 | a [post update] [a] | +| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | Chi [a] | | by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | | by_reference.cpp:92:3:92:20 | Chi [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | -| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:92:3:92:20 | Chi [array content] | -| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | -| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | -| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | +| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:3:92:20 | Chi [array content] | | by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | | by_reference.cpp:96:3:96:19 | Chi [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | -| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:96:3:96:19 | Chi [array content] | -| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | -| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | -| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | -| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | -| by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | by_reference.cpp:110:14:110:25 | inner_nested [a, a] | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | by_reference.cpp:104:22:104:22 | a [post update] [a] | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | -| by_reference.cpp:104:22:104:22 | a [post update] [a] | by_reference.cpp:112:14:112:14 | a [a] | -| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | -| by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | by_reference.cpp:114:16:114:27 | inner_nested [a, a] | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | by_reference.cpp:108:24:108:24 | a [post update] [a] | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | -| by_reference.cpp:108:24:108:24 | a [post update] [a] | by_reference.cpp:116:16:116:16 | a [a] | -| by_reference.cpp:110:14:110:25 | inner_nested [a, a] | by_reference.cpp:110:27:110:27 | a [a] | -| by_reference.cpp:110:27:110:27 | a [a] | by_reference.cpp:110:27:110:27 | a | -| by_reference.cpp:112:14:112:14 | a [a] | by_reference.cpp:112:14:112:14 | a | -| by_reference.cpp:114:16:114:27 | inner_nested [a, a] | by_reference.cpp:114:29:114:29 | a [a] | -| by_reference.cpp:114:29:114:29 | a [a] | by_reference.cpp:114:29:114:29 | a | -| by_reference.cpp:116:16:116:16 | a [a] | by_reference.cpp:116:16:116:16 | a | -| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | -| by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | by_reference.cpp:130:14:130:25 | inner_nested [a, a] | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument | by_reference.cpp:124:21:124:21 | a [post update] [a] | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | taint_a_ref output argument | -| by_reference.cpp:124:21:124:21 | a [post update] [a] | by_reference.cpp:132:14:132:14 | a [a] | -| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | -| by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | by_reference.cpp:134:16:134:27 | inner_nested [a, a] | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument | by_reference.cpp:128:23:128:23 | a [post update] [a] | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | taint_a_ref output argument | -| by_reference.cpp:128:23:128:23 | a [post update] [a] | by_reference.cpp:136:16:136:16 | a [a] | -| by_reference.cpp:130:14:130:25 | inner_nested [a, a] | by_reference.cpp:130:27:130:27 | a [a] | -| by_reference.cpp:130:27:130:27 | a [a] | by_reference.cpp:130:27:130:27 | a | -| by_reference.cpp:132:14:132:14 | a [a] | by_reference.cpp:132:14:132:14 | a | -| by_reference.cpp:134:16:134:27 | inner_nested [a, a] | by_reference.cpp:134:29:134:29 | a [a] | -| by_reference.cpp:134:29:134:29 | a [a] | by_reference.cpp:134:29:134:29 | a | -| by_reference.cpp:136:16:136:16 | a [a] | by_reference.cpp:136:16:136:16 | a | -| by_reference.cpp:140:3:140:27 | Chi [array content] | by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | -| by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | by_reference.cpp:140:3:140:27 | Chi [array content] | -| by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | -| by_reference.cpp:140:9:140:27 | (char *)... | by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | -| by_reference.cpp:140:9:140:27 | (const char *)... | by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | -| by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument | by_reference.cpp:146:8:146:8 | s | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | by_reference.cpp:145:15:145:16 | taint_a_ptr output argument | +| by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:96:3:96:19 | Chi [array content] | +| by_reference.cpp:102:21:102:39 | Chi [a] | by_reference.cpp:110:27:110:27 | a | +| by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | by_reference.cpp:102:21:102:39 | Chi [a] | +| by_reference.cpp:104:15:104:22 | Chi | by_reference.cpp:104:15:104:22 | Chi [a] | +| by_reference.cpp:104:15:104:22 | Chi [a] | by_reference.cpp:112:14:112:14 | a | +| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | by_reference.cpp:104:15:104:22 | Chi | +| by_reference.cpp:106:21:106:41 | Chi [a] | by_reference.cpp:114:29:114:29 | a | +| by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | by_reference.cpp:106:21:106:41 | Chi [a] | +| by_reference.cpp:108:15:108:24 | Chi | by_reference.cpp:108:15:108:24 | Chi [a] | +| by_reference.cpp:108:15:108:24 | Chi [a] | by_reference.cpp:116:16:116:16 | a | +| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | by_reference.cpp:108:15:108:24 | Chi | +| by_reference.cpp:122:21:122:38 | Chi [a] | by_reference.cpp:130:27:130:27 | a | +| by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | by_reference.cpp:122:21:122:38 | Chi [a] | +| by_reference.cpp:124:15:124:21 | Chi | by_reference.cpp:124:15:124:21 | Chi [a] | +| by_reference.cpp:124:15:124:21 | Chi [a] | by_reference.cpp:132:14:132:14 | a | +| by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | by_reference.cpp:124:15:124:21 | Chi | +| by_reference.cpp:126:21:126:40 | Chi [a] | by_reference.cpp:134:29:134:29 | a | +| by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | by_reference.cpp:126:21:126:40 | Chi [a] | +| by_reference.cpp:128:15:128:23 | Chi | by_reference.cpp:128:15:128:23 | Chi [a] | +| by_reference.cpp:128:15:128:23 | Chi [a] | by_reference.cpp:136:16:136:16 | a | +| by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | by_reference.cpp:128:15:128:23 | Chi | | complex.cpp:40:17:40:17 | *b [a_] | complex.cpp:42:18:42:18 | call to a | +| complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | Chi [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:42:16:42:16 | a output argument [b_] | | complex.cpp:40:17:40:17 | *b [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:40:17:40:17 | *b [f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, a_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:42:10:42:14 | inner [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:42:16:42:16 | a output argument [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, a_] | complex.cpp:42:16:42:16 | f [f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, b_] | complex.cpp:42:16:42:16 | f [f, b_] | -| complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | complex.cpp:42:16:42:16 | f [f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | -| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:42:16:42:16 | f [post update] [f, b_] | +| complex.cpp:42:16:42:16 | Chi [b_] | complex.cpp:43:18:43:18 | call to b | +| complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:42:16:42:16 | Chi [b_] | | complex.cpp:42:16:42:16 | a output argument [b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | -| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:42:16:42:16 | f [f, a_] | complex.cpp:42:18:42:18 | call to a | -| complex.cpp:42:16:42:16 | f [f, b_] | complex.cpp:42:16:42:16 | a output argument [b_] | -| complex.cpp:42:16:42:16 | f [f, f, f, a_] | complex.cpp:42:10:42:14 | inner [f, f, a_] | -| complex.cpp:42:16:42:16 | f [post update] [f, b_] | complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | -| complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | -| complex.cpp:43:10:43:14 | inner [f, f, b_] | complex.cpp:43:16:43:16 | f [f, b_] | -| complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | complex.cpp:43:16:43:16 | f [f, f, f, b_] | -| complex.cpp:43:16:43:16 | f [f, b_] | complex.cpp:43:18:43:18 | call to b | -| complex.cpp:43:16:43:16 | f [f, f, f, b_] | complex.cpp:43:10:43:14 | inner [f, f, b_] | -| complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:53:12:53:12 | f [post update] [f, a_] | complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | +| complex.cpp:53:12:53:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | | complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:53:12:53:12 | f [post update] [f, a_] | +| complex.cpp:53:12:53:12 | setA output argument [a_] | complex.cpp:53:12:53:12 | Chi [a_] | | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:53:12:53:12 | setA output argument [a_] | -| complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | complex.cpp:40:17:40:17 | *b [f, f, b_] | -| complex.cpp:54:12:54:12 | f [post update] [f, b_] | complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | +| complex.cpp:54:12:54:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | | complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:54:12:54:12 | f [post update] [f, b_] | +| complex.cpp:54:12:54:12 | setB output argument [b_] | complex.cpp:54:12:54:12 | Chi [b_] | | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:54:12:54:12 | setB output argument [b_] | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:56:6:56:10 | inner [f, f, a_] | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | -| complex.cpp:55:12:55:12 | f [post update] [f, a_] | complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:56:12:56:12 | Chi [a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:55:12:55:12 | f [post update] [f, a_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:55:12:55:12 | Chi [a_] | +| complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | Chi [a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:55:12:55:12 | setA output argument [a_] | -| complex.cpp:56:6:56:10 | inner [f, f, a_] | complex.cpp:56:12:56:12 | f [f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | complex.cpp:40:17:40:17 | *b [f, f, b_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | -| complex.cpp:56:12:56:12 | f [f, a_] | complex.cpp:56:12:56:12 | setB output argument [a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, a_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, b_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | -| complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | +| complex.cpp:56:12:56:12 | Chi [a_] | complex.cpp:40:17:40:17 | *b [a_] | +| complex.cpp:56:12:56:12 | Chi [b_] | complex.cpp:40:17:40:17 | *b [b_] | | complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:40:17:40:17 | *b [a_] | -| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:56:12:56:12 | f [post update] [f, a_] | +| complex.cpp:56:12:56:12 | setB output argument [a_] | complex.cpp:56:12:56:12 | Chi [a_] | | complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:40:17:40:17 | *b [b_] | -| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:56:12:56:12 | f [post update] [f, b_] | -| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | complex.cpp:40:17:40:17 | *b [f, f, a_] | -| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | +| complex.cpp:56:12:56:12 | setB output argument [b_] | complex.cpp:56:12:56:12 | Chi [b_] | | complex.cpp:56:19:56:28 | call to user_input | complex.cpp:56:12:56:12 | setB output argument [b_] | | constructors.cpp:26:15:26:15 | *f [a_] | constructors.cpp:28:12:28:12 | call to a | | constructors.cpp:26:15:26:15 | *f [b_] | constructors.cpp:28:10:28:10 | a output argument [b_] | @@ -288,25 +182,21 @@ edges | simple.cpp:42:5:42:5 | setB output argument [a_] | simple.cpp:26:15:26:15 | *f [a_] | | simple.cpp:42:5:42:5 | setB output argument [b_] | simple.cpp:26:15:26:15 | *f [b_] | | simple.cpp:42:12:42:21 | call to user_input | simple.cpp:42:5:42:5 | setB output argument [b_] | -| simple.cpp:65:7:65:7 | i [post update] [i] | simple.cpp:67:13:67:13 | i [i] | -| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:7:65:7 | i [post update] [i] | -| simple.cpp:67:13:67:13 | i [i] | simple.cpp:67:13:67:13 | i | -| simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | simple.cpp:84:14:84:20 | call to getf2f1 | -| simple.cpp:83:12:83:13 | f1 [post update] [f1] | simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | -| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:12:83:13 | f1 [post update] [f1] | -| simple.cpp:92:7:92:7 | i [post update] [i] | simple.cpp:94:13:94:13 | i [i] | -| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:7:92:7 | i [post update] [i] | -| simple.cpp:94:13:94:13 | i [i] | simple.cpp:94:13:94:13 | i | -| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a [a] | -| struct_init.c:15:12:15:12 | a [a] | struct_init.c:15:12:15:12 | a | -| struct_init.c:20:17:20:36 | a [post update] [a] | struct_init.c:14:24:14:25 | *ab [a] | -| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | a [post update] [a] | +| simple.cpp:65:5:65:22 | Store [i] | simple.cpp:66:12:66:12 | Store [i] | +| simple.cpp:65:11:65:20 | call to user_input | simple.cpp:65:5:65:22 | Store [i] | +| simple.cpp:66:12:66:12 | Store [i] | simple.cpp:67:13:67:13 | i | +| simple.cpp:83:9:83:28 | Chi [f1] | simple.cpp:84:14:84:20 | call to getf2f1 | +| simple.cpp:83:17:83:26 | call to user_input | simple.cpp:83:9:83:28 | Chi [f1] | +| simple.cpp:92:5:92:22 | Store [i] | simple.cpp:93:20:93:20 | Store [i] | +| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | Store [i] | +| simple.cpp:93:20:93:20 | Store [i] | simple.cpp:94:13:94:13 | i | +| struct_init.c:14:24:14:25 | *ab [a] | struct_init.c:15:12:15:12 | a | +| struct_init.c:20:20:20:29 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:22:11:22:11 | a | -| struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | -| struct_init.c:27:5:27:23 | a [post update] [a] | struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | -| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | a [post update] [a] | +| struct_init.c:27:7:27:16 | Chi [a] | struct_init.c:14:24:14:25 | *ab [a] | +| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:7:27:16 | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:31:23:31:23 | a | -| struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | struct_init.c:14:24:14:25 | *ab [a] | nodes | A.cpp:55:5:55:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:55:12:55:19 | (C *)... | semmle.label | (C *)... | @@ -316,75 +206,66 @@ nodes | A.cpp:57:17:57:23 | new | semmle.label | new | | A.cpp:57:28:57:30 | call to get | semmle.label | call to get | | A.cpp:98:12:98:18 | new | semmle.label | new | -| A.cpp:100:9:100:9 | a [post update] [a] | semmle.label | a [post update] [a] | +| A.cpp:100:5:100:13 | Chi [a] | semmle.label | Chi [a] | | A.cpp:103:14:103:14 | *c [a] | semmle.label | *c [a] | | A.cpp:107:16:107:16 | a | semmle.label | a | -| A.cpp:107:16:107:16 | a [a] | semmle.label | a [a] | | A.cpp:126:5:126:5 | Chi [c] | semmle.label | Chi [c] | | A.cpp:126:5:126:5 | set output argument [c] | semmle.label | set output argument [c] | | A.cpp:126:12:126:18 | new | semmle.label | new | +| A.cpp:131:8:131:8 | Chi [c] | semmle.label | Chi [c] | | A.cpp:131:8:131:8 | f7 output argument [c] | semmle.label | f7 output argument [c] | | A.cpp:132:13:132:13 | c | semmle.label | c | -| A.cpp:132:13:132:13 | c [c] | semmle.label | c [c] | | A.cpp:142:7:142:20 | Chi [c] | semmle.label | Chi [c] | -| A.cpp:142:10:142:10 | c [post update] [c] | semmle.label | c [post update] [c] | | A.cpp:142:14:142:20 | new | semmle.label | new | | A.cpp:143:7:143:31 | Chi [b] | semmle.label | Chi [b] | -| A.cpp:143:13:143:13 | b [post update] [b] | semmle.label | b [post update] [b] | | A.cpp:143:25:143:31 | new | semmle.label | new | | A.cpp:150:12:150:18 | new | semmle.label | new | +| A.cpp:151:12:151:24 | Chi [b] | semmle.label | Chi [b] | | A.cpp:151:12:151:24 | D output argument [b] | semmle.label | D output argument [b] | +| A.cpp:151:18:151:18 | Chi [c] | semmle.label | Chi [c] | | A.cpp:151:18:151:18 | D output argument [c] | semmle.label | D output argument [c] | | A.cpp:152:13:152:13 | b | semmle.label | b | -| A.cpp:152:13:152:13 | b [b] | semmle.label | b [b] | | A.cpp:154:13:154:13 | c | semmle.label | c | -| A.cpp:154:13:154:13 | c [c] | semmle.label | c [c] | | C.cpp:18:12:18:18 | C output argument [s1] | semmle.label | C output argument [s1] | | C.cpp:18:12:18:18 | C output argument [s3] | semmle.label | C output argument [s3] | -| C.cpp:22:9:22:22 | s1 [post update] [s1] | semmle.label | s1 [post update] [s1] | +| C.cpp:22:12:22:21 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:22:12:22:21 | new | semmle.label | new | | C.cpp:24:5:24:25 | Chi [s1] | semmle.label | Chi [s1] | | C.cpp:24:5:24:25 | Chi [s3] | semmle.label | Chi [s3] | -| C.cpp:24:11:24:12 | s3 [post update] [s3] | semmle.label | s3 [post update] [s3] | | C.cpp:24:16:24:25 | new | semmle.label | new | | C.cpp:27:8:27:11 | *#this [s1] | semmle.label | *#this [s1] | | C.cpp:27:8:27:11 | *#this [s3] | semmle.label | *#this [s3] | | C.cpp:29:10:29:11 | s1 | semmle.label | s1 | -| C.cpp:29:10:29:11 | s1 [s1] | semmle.label | s1 [s1] | | C.cpp:31:10:31:11 | s3 | semmle.label | s3 | -| C.cpp:31:10:31:11 | s3 [s3] | semmle.label | s3 [s3] | | aliasing.cpp:9:3:9:22 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:9:6:9:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:13:3:13:21 | Chi [m1] | semmle.label | Chi [m1] | -| aliasing.cpp:13:5:13:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | | aliasing.cpp:13:10:13:19 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:25:17:25:19 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:25:17:25:19 | pointerSetter output argument [m1] | semmle.label | pointerSetter output argument [m1] | +| aliasing.cpp:26:19:26:20 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:26:19:26:20 | referenceSetter output argument [m1] | semmle.label | referenceSetter output argument [m1] | | aliasing.cpp:29:11:29:12 | m1 | semmle.label | m1 | -| aliasing.cpp:29:11:29:12 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:30:11:30:12 | m1 | semmle.label | m1 | -| aliasing.cpp:30:11:30:12 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:37:13:37:22 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:38:11:38:12 | m1 | semmle.label | m1 | | aliasing.cpp:42:11:42:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:43:13:43:14 | m1 | semmle.label | m1 | -| aliasing.cpp:60:6:60:7 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:60:3:60:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input | +| aliasing.cpp:61:13:61:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:62:14:62:15 | m1 | semmle.label | m1 | -| aliasing.cpp:62:14:62:15 | m1 [m1] | semmle.label | m1 [m1] | | aliasing.cpp:79:11:79:20 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:80:12:80:13 | m1 | semmle.label | m1 | | aliasing.cpp:86:10:86:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:87:12:87:13 | m1 | semmle.label | m1 | | aliasing.cpp:92:12:92:21 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 | -| aliasing.cpp:98:5:98:6 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | +| aliasing.cpp:98:3:98:21 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:98:10:98:19 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:100:14:100:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:102:8:102:10 | * ... | semmle.label | * ... | | aliasing.cpp:106:3:106:20 | Chi [array content] | semmle.label | Chi [array content] | -| aliasing.cpp:106:3:106:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input | | aliasing.cpp:121:15:121:16 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:121:15:121:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | @@ -404,42 +285,19 @@ nodes | aliasing.cpp:164:15:164:20 | Chi [array content] | semmle.label | Chi [array content] | | aliasing.cpp:164:15:164:20 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | | aliasing.cpp:165:8:165:16 | access to array | semmle.label | access to array | -| aliasing.cpp:175:15:175:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| aliasing.cpp:175:15:175:22 | Chi | semmle.label | Chi | +| aliasing.cpp:175:15:175:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:175:15:175:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:175:19:175:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:175:21:175:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:176:11:176:11 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:176:13:176:14 | m1 | semmle.label | m1 | -| aliasing.cpp:176:13:176:14 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:187:15:187:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| aliasing.cpp:187:15:187:22 | Chi | semmle.label | Chi | +| aliasing.cpp:187:15:187:22 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:187:15:187:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:187:19:187:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:187:21:187:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:189:13:189:13 | s [s, m1] | semmle.label | s [s, m1] | +| aliasing.cpp:188:13:188:14 | Store [m1] | semmle.label | Store [m1] | | aliasing.cpp:189:15:189:16 | m1 | semmle.label | m1 | -| aliasing.cpp:189:15:189:16 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:200:15:200:24 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| aliasing.cpp:200:15:200:24 | Chi | semmle.label | Chi | +| aliasing.cpp:200:15:200:24 | Chi [m1] | semmle.label | Chi [m1] | | aliasing.cpp:200:15:200:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:200:21:200:21 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:200:23:200:24 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:201:13:201:13 | s [s, m1] | semmle.label | s [s, m1] | | aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | -| aliasing.cpp:201:15:201:16 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:211:6:211:6 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:211:8:211:9 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:212:12:212:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:212:12:212:12 | s [s, m1] | semmle.label | s [s, m1] | -| aliasing.cpp:213:10:213:11 | m1 | semmle.label | m1 | -| aliasing.cpp:213:10:213:11 | m1 [m1] | semmle.label | m1 [m1] | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | -| aliasing.cpp:225:15:225:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| aliasing.cpp:225:19:225:19 | s [post update] [s, m1] | semmle.label | s [post update] [s, m1] | -| aliasing.cpp:225:21:225:22 | m1 [post update] [m1] | semmle.label | m1 [post update] [m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:226:12:226:12 | s [s, m1] | semmle.label | s [s, m1] | -| aliasing.cpp:227:10:227:11 | m1 | semmle.label | m1 | -| aliasing.cpp:227:10:227:11 | m1 [m1] | semmle.label | m1 [m1] | | arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input | | arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array | | arrays.cpp:9:8:9:11 | * ... | semmle.label | * ... | @@ -461,111 +319,60 @@ nodes | by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA | | by_reference.cpp:84:3:84:25 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:84:10:84:10 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:88:3:88:24 | Chi [a] | semmle.label | Chi [a] | -| by_reference.cpp:88:9:88:9 | a [post update] [a] | semmle.label | a [post update] [a] | | by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:92:3:92:20 | Chi [array content] | semmle.label | Chi [array content] | -| by_reference.cpp:92:3:92:20 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input | | by_reference.cpp:96:3:96:19 | Chi [array content] | semmle.label | Chi [array content] | -| by_reference.cpp:96:3:96:19 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | by_reference.cpp:96:8:96:17 | call to user_input | semmle.label | call to user_input | +| by_reference.cpp:102:21:102:39 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:102:21:102:39 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:102:28:102:39 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:104:15:104:22 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| by_reference.cpp:104:15:104:22 | Chi | semmle.label | Chi | +| by_reference.cpp:104:15:104:22 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:104:15:104:22 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| by_reference.cpp:104:22:104:22 | a [post update] [a] | semmle.label | a [post update] [a] | +| by_reference.cpp:106:21:106:41 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:106:21:106:41 | taint_inner_a_ptr output argument [a] | semmle.label | taint_inner_a_ptr output argument [a] | -| by_reference.cpp:106:30:106:41 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:108:15:108:24 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | +| by_reference.cpp:108:15:108:24 | Chi | semmle.label | Chi | +| by_reference.cpp:108:15:108:24 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:108:15:108:24 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| by_reference.cpp:108:24:108:24 | a [post update] [a] | semmle.label | a [post update] [a] | -| by_reference.cpp:110:14:110:25 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:110:27:110:27 | a | semmle.label | a | -| by_reference.cpp:110:27:110:27 | a [a] | semmle.label | a [a] | | by_reference.cpp:112:14:112:14 | a | semmle.label | a | -| by_reference.cpp:112:14:112:14 | a [a] | semmle.label | a [a] | -| by_reference.cpp:114:16:114:27 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:114:29:114:29 | a | semmle.label | a | -| by_reference.cpp:114:29:114:29 | a [a] | semmle.label | a [a] | | by_reference.cpp:116:16:116:16 | a | semmle.label | a | -| by_reference.cpp:116:16:116:16 | a [a] | semmle.label | a [a] | +| by_reference.cpp:122:21:122:38 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:122:21:122:38 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:122:27:122:38 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:124:15:124:21 | taint_a_ref output argument | semmle.label | taint_a_ref output argument | +| by_reference.cpp:124:15:124:21 | Chi | semmle.label | Chi | +| by_reference.cpp:124:15:124:21 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:124:15:124:21 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | -| by_reference.cpp:124:21:124:21 | a [post update] [a] | semmle.label | a [post update] [a] | +| by_reference.cpp:126:21:126:40 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:126:21:126:40 | taint_inner_a_ref output argument [a] | semmle.label | taint_inner_a_ref output argument [a] | -| by_reference.cpp:126:29:126:40 | inner_nested [post update] [a, a] | semmle.label | inner_nested [post update] [a, a] | -| by_reference.cpp:128:15:128:23 | taint_a_ref output argument | semmle.label | taint_a_ref output argument | +| by_reference.cpp:128:15:128:23 | Chi | semmle.label | Chi | +| by_reference.cpp:128:15:128:23 | Chi [a] | semmle.label | Chi [a] | | by_reference.cpp:128:15:128:23 | taint_a_ref output argument [array content] | semmle.label | taint_a_ref output argument [array content] | -| by_reference.cpp:128:23:128:23 | a [post update] [a] | semmle.label | a [post update] [a] | -| by_reference.cpp:130:14:130:25 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:130:27:130:27 | a | semmle.label | a | -| by_reference.cpp:130:27:130:27 | a [a] | semmle.label | a [a] | | by_reference.cpp:132:14:132:14 | a | semmle.label | a | -| by_reference.cpp:132:14:132:14 | a [a] | semmle.label | a [a] | -| by_reference.cpp:134:16:134:27 | inner_nested [a, a] | semmle.label | inner_nested [a, a] | | by_reference.cpp:134:29:134:29 | a | semmle.label | a | -| by_reference.cpp:134:29:134:29 | a [a] | semmle.label | a [a] | | by_reference.cpp:136:16:136:16 | a | semmle.label | a | -| by_reference.cpp:136:16:136:16 | a [a] | semmle.label | a [a] | -| by_reference.cpp:140:3:140:27 | Chi [array content] | semmle.label | Chi [array content] | -| by_reference.cpp:140:3:140:27 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | -| by_reference.cpp:140:9:140:27 | (char *)... | semmle.label | (char *)... | -| by_reference.cpp:140:9:140:27 | (const char *)... | semmle.label | (const char *)... | -| by_reference.cpp:140:16:140:25 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument | semmle.label | taint_a_ptr output argument | -| by_reference.cpp:145:15:145:16 | taint_a_ptr output argument [array content] | semmle.label | taint_a_ptr output argument [array content] | -| by_reference.cpp:146:8:146:8 | s | semmle.label | s | | complex.cpp:40:17:40:17 | *b [a_] | semmle.label | *b [a_] | | complex.cpp:40:17:40:17 | *b [b_] | semmle.label | *b [b_] | -| complex.cpp:40:17:40:17 | *b [f, f, a_] | semmle.label | *b [f, f, a_] | -| complex.cpp:40:17:40:17 | *b [f, f, b_] | semmle.label | *b [f, f, b_] | -| complex.cpp:40:17:40:17 | *b [f, f, f, f, a_] | semmle.label | *b [f, f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, a_] | semmle.label | inner [f, f, a_] | -| complex.cpp:42:10:42:14 | inner [f, f, b_] | semmle.label | inner [f, f, b_] | -| complex.cpp:42:10:42:14 | inner [f, f, f, f, a_] | semmle.label | inner [f, f, f, f, a_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | -| complex.cpp:42:10:42:14 | inner [post update] [f, f, f, f, b_] | semmle.label | inner [post update] [f, f, f, f, b_] | +| complex.cpp:42:16:42:16 | Chi [b_] | semmle.label | Chi [b_] | | complex.cpp:42:16:42:16 | a output argument [b_] | semmle.label | a output argument [b_] | -| complex.cpp:42:16:42:16 | a output argument [f, f, b_] | semmle.label | a output argument [f, f, b_] | -| complex.cpp:42:16:42:16 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:42:16:42:16 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:42:16:42:16 | f [f, f, f, a_] | semmle.label | f [f, f, f, a_] | -| complex.cpp:42:16:42:16 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | -| complex.cpp:42:16:42:16 | f [post update] [f, f, f, b_] | semmle.label | f [post update] [f, f, f, b_] | | complex.cpp:42:18:42:18 | call to a | semmle.label | call to a | -| complex.cpp:43:10:43:14 | inner [f, f, b_] | semmle.label | inner [f, f, b_] | -| complex.cpp:43:10:43:14 | inner [f, f, f, f, b_] | semmle.label | inner [f, f, f, f, b_] | -| complex.cpp:43:16:43:16 | f [f, b_] | semmle.label | f [f, b_] | -| complex.cpp:43:16:43:16 | f [f, f, f, b_] | semmle.label | f [f, f, f, b_] | | complex.cpp:43:18:43:18 | call to b | semmle.label | call to b | -| complex.cpp:53:6:53:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | -| complex.cpp:53:12:53:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | +| complex.cpp:53:12:53:12 | Chi [a_] | semmle.label | Chi [a_] | | complex.cpp:53:12:53:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:53:19:53:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:54:6:54:10 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | -| complex.cpp:54:12:54:12 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | +| complex.cpp:54:12:54:12 | Chi [b_] | semmle.label | Chi [b_] | | complex.cpp:54:12:54:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | | complex.cpp:54:19:54:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:55:6:55:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | -| complex.cpp:55:12:55:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | +| complex.cpp:55:12:55:12 | Chi [a_] | semmle.label | Chi [a_] | | complex.cpp:55:12:55:12 | setA output argument [a_] | semmle.label | setA output argument [a_] | | complex.cpp:55:19:55:28 | call to user_input | semmle.label | call to user_input | -| complex.cpp:56:6:56:10 | inner [f, f, a_] | semmle.label | inner [f, f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, a_] | semmle.label | inner [post update] [f, f, a_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, b_] | semmle.label | inner [post update] [f, f, b_] | -| complex.cpp:56:6:56:10 | inner [post update] [f, f, f, f, a_] | semmle.label | inner [post update] [f, f, f, f, a_] | -| complex.cpp:56:12:56:12 | f [f, a_] | semmle.label | f [f, a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, a_] | semmle.label | f [post update] [f, a_] | -| complex.cpp:56:12:56:12 | f [post update] [f, b_] | semmle.label | f [post update] [f, b_] | -| complex.cpp:56:12:56:12 | f [post update] [f, f, f, a_] | semmle.label | f [post update] [f, f, f, a_] | +| complex.cpp:56:12:56:12 | Chi [a_] | semmle.label | Chi [a_] | +| complex.cpp:56:12:56:12 | Chi [b_] | semmle.label | Chi [b_] | | complex.cpp:56:12:56:12 | setB output argument [a_] | semmle.label | setB output argument [a_] | | complex.cpp:56:12:56:12 | setB output argument [b_] | semmle.label | setB output argument [b_] | -| complex.cpp:56:12:56:12 | setB output argument [f, f, a_] | semmle.label | setB output argument [f, f, a_] | | complex.cpp:56:19:56:28 | call to user_input | semmle.label | call to user_input | | constructors.cpp:26:15:26:15 | *f [a_] | semmle.label | *f [a_] | | constructors.cpp:26:15:26:15 | *f [b_] | semmle.label | *f [b_] | @@ -594,29 +401,25 @@ nodes | simple.cpp:42:5:42:5 | setB output argument [a_] | semmle.label | setB output argument [a_] | | simple.cpp:42:5:42:5 | setB output argument [b_] | semmle.label | setB output argument [b_] | | simple.cpp:42:12:42:21 | call to user_input | semmle.label | call to user_input | -| simple.cpp:65:7:65:7 | i [post update] [i] | semmle.label | i [post update] [i] | +| simple.cpp:65:5:65:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:65:11:65:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:66:12:66:12 | Store [i] | semmle.label | Store [i] | | simple.cpp:67:13:67:13 | i | semmle.label | i | -| simple.cpp:67:13:67:13 | i [i] | semmle.label | i [i] | -| simple.cpp:83:9:83:10 | f2 [post update] [f1, f1] | semmle.label | f2 [post update] [f1, f1] | -| simple.cpp:83:12:83:13 | f1 [post update] [f1] | semmle.label | f1 [post update] [f1] | +| simple.cpp:83:9:83:28 | Chi [f1] | semmle.label | Chi [f1] | | simple.cpp:83:17:83:26 | call to user_input | semmle.label | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | semmle.label | call to getf2f1 | -| simple.cpp:92:7:92:7 | i [post update] [i] | semmle.label | i [post update] [i] | +| simple.cpp:92:5:92:22 | Store [i] | semmle.label | Store [i] | | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | +| simple.cpp:93:20:93:20 | Store [i] | semmle.label | Store [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | -| simple.cpp:94:13:94:13 | i [i] | semmle.label | i [i] | | struct_init.c:14:24:14:25 | *ab [a] | semmle.label | *ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | -| struct_init.c:15:12:15:12 | a [a] | semmle.label | a [a] | -| struct_init.c:20:17:20:36 | a [post update] [a] | semmle.label | a [post update] [a] | +| struct_init.c:20:20:20:29 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input | | struct_init.c:22:11:22:11 | a | semmle.label | a | -| struct_init.c:26:23:29:3 | nestedAB [post update] [nestedAB, a] | semmle.label | nestedAB [post update] [nestedAB, a] | -| struct_init.c:27:5:27:23 | a [post update] [a] | semmle.label | a [post update] [a] | +| struct_init.c:27:7:27:16 | Chi [a] | semmle.label | Chi [a] | | struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input | | struct_init.c:31:23:31:23 | a | semmle.label | a | -| struct_init.c:36:17:36:24 | nestedAB [nestedAB, a] | semmle.label | nestedAB [nestedAB, a] | #select | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | (C *)... | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | (C *)... | (C *)... | | A.cpp:56:13:56:15 | call to get | A.cpp:55:12:55:19 | new | A.cpp:56:13:56:15 | call to get | call to get flows from $@ | A.cpp:55:12:55:19 | new | new | @@ -646,8 +449,6 @@ nodes | aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | -| aliasing.cpp:213:10:213:11 | m1 | aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:213:10:213:11 | m1 | m1 flows from $@ | aliasing.cpp:211:13:211:22 | call to user_input | call to user_input | -| aliasing.cpp:227:10:227:11 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:227:10:227:11 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:10:8:10:15 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | @@ -665,9 +466,6 @@ nodes | by_reference.cpp:132:14:132:14 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:132:14:132:14 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input | | 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: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 | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:9:140:27 | (char *)... | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:9:140:27 | (char *)... | (char *)... | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:9:140:27 | (const char *)... | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:9:140:27 | (const char *)... | (const char *)... | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:16:140:25 | 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 d7939750db6..996836a65b4 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 @@ -1,12 +1,12 @@ | A.cpp:25:13:25:13 | c | AST only | | A.cpp:27:28:27:28 | c | AST only | -| A.cpp:28:29:28:29 | this | IR only | | A.cpp:31:20:31:20 | c | AST only | | A.cpp:40:5:40:6 | cc | AST only | | A.cpp:41:5:41:6 | ct | AST only | | A.cpp:42:10:42:12 | & ... | AST only | | A.cpp:43:10:43:12 | & ... | AST only | | A.cpp:48:20:48:20 | c | AST only | +| A.cpp:49:10:49:10 | b | AST only | | A.cpp:49:13:49:13 | c | AST only | | A.cpp:55:5:55:5 | b | AST only | | A.cpp:56:10:56:10 | b | AST only | @@ -14,11 +14,15 @@ | A.cpp:57:28:57:30 | call to get | AST only | | A.cpp:64:10:64:15 | this | AST only | | A.cpp:64:17:64:18 | b1 | AST only | +| A.cpp:65:10:65:11 | b1 | AST only | | A.cpp:65:14:65:14 | c | AST only | +| A.cpp:66:10:66:11 | b2 | AST only | | A.cpp:66:14:66:14 | c | AST only | | A.cpp:73:10:73:19 | this | AST only | | A.cpp:73:21:73:22 | b1 | AST only | +| A.cpp:74:10:74:11 | b1 | AST only | | A.cpp:74:14:74:14 | c | AST only | +| A.cpp:75:10:75:11 | b2 | AST only | | A.cpp:75:14:75:14 | c | AST only | | A.cpp:81:10:81:15 | this | AST only | | A.cpp:81:17:81:18 | b1 | AST only | @@ -30,61 +34,85 @@ | A.cpp:100:9:100:9 | a | AST only | | A.cpp:101:5:101:6 | this | AST only | | A.cpp:101:8:101:9 | c1 | AST only | +| A.cpp:107:12:107:13 | c1 | AST only | | A.cpp:107:16:107:16 | a | AST only | +| A.cpp:120:12:120:13 | c1 | AST only | | A.cpp:120:16:120:16 | a | AST only | | A.cpp:126:5:126:5 | b | AST only | | A.cpp:131:5:131:6 | this | AST only | | A.cpp:131:8:131:8 | b | AST only | +| A.cpp:132:10:132:10 | b | AST only | | A.cpp:132:13:132:13 | c | AST only | | A.cpp:142:10:142:10 | c | AST only | | A.cpp:143:13:143:13 | b | AST only | | A.cpp:151:18:151:18 | b | AST only | | A.cpp:151:21:151:21 | this | AST only | +| A.cpp:152:10:152:10 | d | AST only | | A.cpp:152:13:152:13 | b | AST only | +| A.cpp:153:10:153:10 | d | AST only | +| A.cpp:153:13:153:13 | b | AST only | | A.cpp:153:16:153:16 | c | AST only | +| A.cpp:154:10:154:10 | b | AST only | | A.cpp:154:13:154:13 | c | AST only | | A.cpp:160:29:160:29 | b | AST only | | A.cpp:161:38:161:39 | l1 | AST only | | A.cpp:162:38:162:39 | l2 | AST only | +| A.cpp:163:10:163:11 | l3 | AST only | | A.cpp:163:14:163:17 | head | AST only | +| A.cpp:164:10:164:11 | l3 | AST only | +| A.cpp:164:14:164:17 | next | AST only | | A.cpp:164:20:164:23 | head | AST only | +| A.cpp:165:10:165:11 | l3 | AST only | +| A.cpp:165:14:165:17 | next | AST only | +| A.cpp:165:20:165:23 | next | AST only | | A.cpp:165:26:165:29 | head | AST only | +| A.cpp:166:10:166:11 | l3 | AST only | +| A.cpp:166:14:166:17 | next | AST only | +| A.cpp:166:20:166:23 | next | AST only | +| A.cpp:166:26:166:29 | next | AST only | | A.cpp:166:32:166:35 | head | AST only | -| A.cpp:167:47:167:50 | l | IR only | +| A.cpp:169:12:169:12 | l | AST only | | A.cpp:169:15:169:18 | head | AST only | | A.cpp:183:7:183:10 | head | AST only | | A.cpp:184:13:184:16 | next | AST only | | B.cpp:7:25:7:25 | e | AST only | | B.cpp:8:25:8:26 | b1 | AST only | +| B.cpp:9:10:9:11 | b2 | AST only | +| B.cpp:9:14:9:17 | box1 | AST only | | B.cpp:9:20:9:24 | elem1 | AST only | +| B.cpp:10:10:10:11 | b2 | AST only | +| B.cpp:10:14:10:17 | box1 | AST only | | B.cpp:10:20:10:24 | elem2 | AST only | | B.cpp:16:37:16:37 | e | AST only | | B.cpp:17:25:17:26 | b1 | AST only | +| B.cpp:18:10:18:11 | b2 | AST only | +| B.cpp:18:14:18:17 | box1 | AST only | | B.cpp:18:20:18:24 | elem1 | AST only | +| B.cpp:19:10:19:11 | b2 | AST only | +| B.cpp:19:14:19:17 | box1 | AST only | | B.cpp:19:20:19:24 | elem2 | AST only | | B.cpp:35:13:35:17 | elem1 | AST only | | B.cpp:36:13:36:17 | elem2 | AST only | | B.cpp:46:13:46:16 | box1 | AST only | | C.cpp:19:5:19:5 | c | AST only | | C.cpp:24:11:24:12 | s3 | AST only | -| C.cpp:29:10:29:11 | this | IR only | -| C.cpp:30:10:30:11 | this | IR only | -| C.cpp:31:10:31:11 | this | IR only | | D.cpp:9:21:9:24 | elem | AST only | -| D.cpp:10:30:10:33 | this | IR only | | D.cpp:11:29:11:32 | elem | AST only | | D.cpp:16:21:16:23 | box | AST only | -| D.cpp:17:30:17:32 | this | IR only | | D.cpp:18:29:18:31 | box | AST only | | D.cpp:22:10:22:11 | b2 | AST only | | D.cpp:22:14:22:20 | call to getBox1 | AST only | | D.cpp:22:25:22:31 | call to getElem | AST only | +| D.cpp:30:5:30:5 | b | AST only | +| D.cpp:30:8:30:10 | box | AST only | | D.cpp:30:13:30:16 | elem | AST only | | D.cpp:31:14:31:14 | b | AST only | +| D.cpp:37:5:37:5 | b | AST only | | D.cpp:37:8:37:10 | box | AST only | | D.cpp:37:21:37:21 | e | AST only | | D.cpp:38:14:38:14 | b | AST only | | D.cpp:44:5:44:5 | b | AST only | +| D.cpp:44:8:44:14 | call to getBox1 | AST only | | D.cpp:44:19:44:22 | elem | AST only | | D.cpp:45:14:45:14 | b | AST only | | D.cpp:51:5:51:5 | b | AST only | @@ -92,14 +120,26 @@ | D.cpp:51:27:51:27 | e | AST only | | D.cpp:52:14:52:14 | b | AST only | | D.cpp:57:5:57:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | boxfield | AST only | +| D.cpp:58:5:58:12 | this | AST only | +| D.cpp:58:15:58:17 | box | AST only | | D.cpp:58:20:58:23 | elem | AST only | | D.cpp:59:5:59:7 | this | AST only | +| D.cpp:64:10:64:17 | boxfield | AST only | +| D.cpp:64:10:64:17 | this | AST only | +| D.cpp:64:20:64:22 | box | AST only | | D.cpp:64:25:64:28 | elem | AST only | +| E.cpp:21:10:21:10 | p | AST only | +| E.cpp:21:13:21:16 | data | AST only | | E.cpp:21:18:21:23 | buffer | AST only | | E.cpp:28:21:28:23 | raw | AST only | +| E.cpp:29:21:29:21 | b | AST only | | E.cpp:29:24:29:29 | buffer | AST only | +| E.cpp:30:21:30:21 | p | AST only | +| E.cpp:30:23:30:26 | data | AST only | | E.cpp:30:28:30:33 | buffer | AST only | | E.cpp:31:10:31:12 | raw | AST only | +| E.cpp:32:10:32:10 | b | AST only | | E.cpp:32:13:32:18 | buffer | AST only | | E.cpp:33:18:33:19 | & ... | AST only | | aliasing.cpp:9:6:9:7 | m1 | AST only | @@ -107,92 +147,79 @@ | aliasing.cpp:17:5:17:6 | m1 | AST only | | aliasing.cpp:25:17:25:19 | & ... | AST only | | aliasing.cpp:26:19:26:20 | s2 | AST only | -| aliasing.cpp:29:11:29:12 | s1 | IR only | -| aliasing.cpp:30:11:30:12 | s2 | IR only | -| aliasing.cpp:31:11:31:12 | s3 | IR only | | aliasing.cpp:37:8:37:9 | m1 | AST only | -| aliasing.cpp:38:11:38:12 | s1 | IR only | | aliasing.cpp:42:6:42:7 | m1 | AST only | -| aliasing.cpp:43:13:43:14 | ref2 | IR only | | aliasing.cpp:49:9:49:10 | m1 | AST only | -| aliasing.cpp:50:11:50:12 | s1 | IR only | | aliasing.cpp:54:6:54:7 | m1 | AST only | -| aliasing.cpp:55:14:55:15 | copy2 | IR only | | aliasing.cpp:60:6:60:7 | m1 | AST only | -| aliasing.cpp:62:14:62:15 | copy2 | IR only | -| aliasing.cpp:71:11:71:11 | w | IR only | | aliasing.cpp:72:5:72:6 | m1 | AST only | -| aliasing.cpp:73:10:73:10 | w | IR only | -| aliasing.cpp:73:12:73:13 | s | IR only | -| aliasing.cpp:78:13:78:13 | w | IR only | | aliasing.cpp:79:6:79:7 | m1 | AST only | -| aliasing.cpp:80:10:80:10 | w | IR only | -| aliasing.cpp:80:12:80:13 | s | IR only | -| aliasing.cpp:85:12:85:12 | w | IR only | | aliasing.cpp:86:5:86:6 | m1 | AST only | -| aliasing.cpp:87:10:87:10 | w | IR only | -| aliasing.cpp:87:12:87:13 | s | IR only | +| aliasing.cpp:92:3:92:3 | w | AST only | | aliasing.cpp:92:7:92:8 | m1 | AST only | -| aliasing.cpp:93:10:93:10 | w | IR only | -| aliasing.cpp:93:12:93:13 | s | IR only | | aliasing.cpp:98:5:98:6 | m1 | AST only | -| aliasing.cpp:101:21:101:22 | s_copy | IR only | | aliasing.cpp:106:3:106:5 | * ... | AST only | | aliasing.cpp:111:15:111:19 | & ... | AST only | -| aliasing.cpp:112:10:112:11 | s | IR only | | aliasing.cpp:121:15:121:16 | xs | AST only | | aliasing.cpp:126:15:126:20 | ... - ... | AST only | | aliasing.cpp:131:15:131:16 | xs | AST only | | aliasing.cpp:136:15:136:17 | + ... | AST only | +| aliasing.cpp:141:15:141:15 | s | AST only | | aliasing.cpp:141:17:141:20 | data | AST only | -| aliasing.cpp:143:10:143:13 | s | IR only | | aliasing.cpp:147:15:147:22 | & ... | AST only | -| aliasing.cpp:148:13:148:14 | access to array | IR only | +| aliasing.cpp:158:15:158:15 | s | AST only | | aliasing.cpp:158:17:158:20 | data | AST only | -| aliasing.cpp:159:11:159:14 | s | IR only | +| aliasing.cpp:164:15:164:15 | s | AST only | | aliasing.cpp:164:17:164:20 | data | AST only | -| aliasing.cpp:165:10:165:13 | s | IR only | | aliasing.cpp:175:15:175:22 | & ... | AST only | -| aliasing.cpp:176:11:176:11 | s2 | IR only | -| aliasing.cpp:176:13:176:14 | s | IR only | +| aliasing.cpp:175:16:175:17 | s2 | AST only | | aliasing.cpp:181:15:181:22 | & ... | AST only | -| aliasing.cpp:182:11:182:11 | s2 | IR only | -| aliasing.cpp:182:13:182:14 | s | IR only | +| aliasing.cpp:181:16:181:17 | s2 | AST only | | aliasing.cpp:187:15:187:22 | & ... | AST only | -| aliasing.cpp:189:13:189:13 | s2_2 | IR only | -| aliasing.cpp:189:15:189:16 | s | IR only | +| aliasing.cpp:187:16:187:17 | s2 | AST only | | aliasing.cpp:194:15:194:22 | & ... | AST only | -| aliasing.cpp:196:13:196:13 | s2_2 | IR only | -| aliasing.cpp:196:15:196:16 | s | IR only | +| aliasing.cpp:194:16:194:17 | s2 | AST only | | aliasing.cpp:200:15:200:24 | & ... | AST only | -| aliasing.cpp:201:13:201:13 | ps2 | IR only | -| aliasing.cpp:201:15:201:16 | s | IR only | +| aliasing.cpp:200:16:200:18 | ps2 | AST only | | aliasing.cpp:205:15:205:24 | & ... | AST only | -| aliasing.cpp:206:13:206:13 | ps2 | IR only | -| aliasing.cpp:206:15:206:16 | s | IR only | -| aliasing.cpp:211:8:211:9 | m1 | AST only | -| aliasing.cpp:212:12:212:12 | s2 | IR only | -| aliasing.cpp:213:10:213:11 | s | IR only | -| aliasing.cpp:218:8:218:9 | m1 | AST only | -| aliasing.cpp:219:12:219:12 | s2 | IR only | -| aliasing.cpp:220:10:220:11 | s | IR only | -| aliasing.cpp:225:15:225:22 | & ... | AST only | -| aliasing.cpp:226:12:226:12 | s2 | IR only | -| aliasing.cpp:227:10:227:11 | s | IR only | -| aliasing.cpp:232:15:232:22 | & ... | AST only | -| aliasing.cpp:233:12:233:12 | s2 | IR only | -| aliasing.cpp:234:10:234:11 | s | IR only | +| aliasing.cpp:205:16:205:18 | ps2 | AST only | | arrays.cpp:6:3:6:8 | access to array | AST only | | arrays.cpp:6:3:6:23 | arr | IR only | | arrays.cpp:15:3:15:10 | * ... | AST only | +| arrays.cpp:36:3:36:3 | o | AST only | +| arrays.cpp:36:5:36:10 | nested | AST only | | arrays.cpp:36:19:36:22 | data | AST only | +| arrays.cpp:37:8:37:8 | o | AST only | +| arrays.cpp:37:8:37:22 | access to array | AST only | +| arrays.cpp:37:10:37:15 | nested | AST only | | arrays.cpp:37:24:37:27 | data | AST only | +| arrays.cpp:38:8:38:8 | o | AST only | +| arrays.cpp:38:8:38:22 | access to array | AST only | +| arrays.cpp:38:10:38:15 | nested | AST only | | arrays.cpp:38:24:38:27 | data | AST only | +| arrays.cpp:42:3:42:3 | o | AST only | +| arrays.cpp:42:3:42:20 | access to array | AST only | +| arrays.cpp:42:5:42:12 | indirect | AST only | | arrays.cpp:42:22:42:25 | data | AST only | +| arrays.cpp:43:8:43:8 | o | AST only | +| arrays.cpp:43:8:43:25 | access to array | AST only | +| arrays.cpp:43:10:43:17 | indirect | AST only | | arrays.cpp:43:27:43:30 | data | AST only | +| arrays.cpp:44:8:44:8 | o | AST only | +| arrays.cpp:44:8:44:25 | access to array | AST only | +| arrays.cpp:44:10:44:17 | indirect | AST only | | arrays.cpp:44:27:44:30 | data | AST only | +| arrays.cpp:48:3:48:3 | o | AST only | +| arrays.cpp:48:3:48:20 | access to array | AST only | +| arrays.cpp:48:5:48:12 | indirect | AST only | | arrays.cpp:48:22:48:25 | data | AST only | +| arrays.cpp:49:8:49:8 | o | AST only | +| arrays.cpp:49:8:49:25 | access to array | AST only | +| arrays.cpp:49:10:49:17 | indirect | AST only | | arrays.cpp:49:27:49:30 | data | AST only | +| arrays.cpp:50:8:50:8 | o | AST only | +| arrays.cpp:50:8:50:25 | access to array | AST only | +| arrays.cpp:50:10:50:17 | indirect | AST only | | arrays.cpp:50:27:50:30 | data | AST only | | by_reference.cpp:12:8:12:8 | a | AST only | | by_reference.cpp:16:11:16:11 | a | AST only | @@ -200,8 +227,6 @@ | by_reference.cpp:20:23:20:27 | value | AST only | | by_reference.cpp:24:19:24:22 | this | AST only | | by_reference.cpp:24:25:24:29 | value | AST only | -| by_reference.cpp:32:15:32:15 | s | IR only | -| by_reference.cpp:36:18:36:18 | this | IR only | | by_reference.cpp:50:3:50:3 | s | AST only | | by_reference.cpp:50:17:50:26 | call to user_input | AST only | | by_reference.cpp:51:10:51:20 | call to getDirectly | AST only | @@ -219,63 +244,87 @@ | by_reference.cpp:92:3:92:5 | * ... | AST only | | by_reference.cpp:96:3:96:4 | pa | AST only | | by_reference.cpp:102:21:102:39 | & ... | AST only | +| by_reference.cpp:103:21:103:25 | outer | AST only | | by_reference.cpp:103:27:103:35 | inner_ptr | AST only | | by_reference.cpp:104:15:104:22 | & ... | AST only | | by_reference.cpp:106:21:106:41 | & ... | AST only | +| by_reference.cpp:107:21:107:26 | pouter | AST only | | by_reference.cpp:107:29:107:37 | inner_ptr | AST only | | by_reference.cpp:108:15:108:24 | & ... | AST only | +| by_reference.cpp:110:8:110:12 | outer | AST only | +| by_reference.cpp:110:14:110:25 | inner_nested | AST only | | by_reference.cpp:110:27:110:27 | a | AST only | +| by_reference.cpp:111:8:111:12 | outer | AST only | +| by_reference.cpp:111:14:111:22 | inner_ptr | AST only | | by_reference.cpp:111:25:111:25 | a | AST only | +| by_reference.cpp:112:8:112:12 | outer | AST only | | by_reference.cpp:112:14:112:14 | a | AST only | +| by_reference.cpp:114:8:114:13 | pouter | AST only | +| by_reference.cpp:114:16:114:27 | inner_nested | AST only | | by_reference.cpp:114:29:114:29 | a | AST only | +| by_reference.cpp:115:8:115:13 | pouter | AST only | +| by_reference.cpp:115:16:115:24 | inner_ptr | AST only | | by_reference.cpp:115:27:115:27 | a | AST only | +| by_reference.cpp:116:8:116:13 | pouter | AST only | | by_reference.cpp:116:16:116:16 | a | AST only | | by_reference.cpp:122:27:122:38 | inner_nested | AST only | | by_reference.cpp:123:21:123:36 | * ... | AST only | +| by_reference.cpp:123:22:123:26 | outer | AST only | | by_reference.cpp:124:21:124:21 | a | AST only | | by_reference.cpp:126:29:126:40 | inner_nested | AST only | | by_reference.cpp:127:21:127:38 | * ... | AST only | +| by_reference.cpp:127:22:127:27 | pouter | AST only | | by_reference.cpp:128:23:128:23 | a | AST only | +| by_reference.cpp:130:8:130:12 | outer | AST only | +| by_reference.cpp:130:14:130:25 | inner_nested | AST only | | by_reference.cpp:130:27:130:27 | a | AST only | +| by_reference.cpp:131:8:131:12 | outer | AST only | +| by_reference.cpp:131:14:131:22 | inner_ptr | AST only | | by_reference.cpp:131:25:131:25 | a | AST only | +| by_reference.cpp:132:8:132:12 | outer | AST only | | by_reference.cpp:132:14:132:14 | a | AST only | +| by_reference.cpp:134:8:134:13 | pouter | AST only | +| by_reference.cpp:134:16:134:27 | inner_nested | AST only | | by_reference.cpp:134:29:134:29 | a | AST only | +| by_reference.cpp:135:8:135:13 | pouter | AST only | +| by_reference.cpp:135:16:135:24 | inner_ptr | AST only | | by_reference.cpp:135:27:135:27 | a | AST only | +| by_reference.cpp:136:8:136:13 | pouter | AST only | | by_reference.cpp:136:16:136:16 | a | AST only | -| by_reference.cpp:140:3:140:5 | * ... | AST only | -| by_reference.cpp:145:15:145:16 | & ... | AST 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 | | complex.cpp:12:22:12:23 | b_ | AST only | +| complex.cpp:42:8:42:8 | b | AST only | | complex.cpp:42:16:42:16 | f | AST only | +| complex.cpp:43:8:43:8 | b | AST only | | complex.cpp:43:16:43:16 | f | AST only | +| complex.cpp:53:3:53:4 | b1 | AST only | | complex.cpp:53:12:53:12 | f | AST only | +| complex.cpp:54:3:54:4 | b2 | AST only | | complex.cpp:54:12:54:12 | f | AST only | +| complex.cpp:55:3:55:4 | b3 | AST only | | complex.cpp:55:12:55:12 | f | AST only | +| complex.cpp:56:3:56:4 | b3 | AST only | | complex.cpp:56:12:56:12 | f | AST only | | complex.cpp:59:7:59:8 | b1 | AST only | | complex.cpp:62:7:62:8 | b2 | AST only | | complex.cpp:65:7:65:8 | b3 | AST only | | complex.cpp:68:7:68:8 | b4 | AST only | | conflated.cpp:10:3:10:7 | * ... | AST only | -| conflated.cpp:11:12:11:12 | ra | IR only | +| conflated.cpp:10:4:10:5 | ra | AST only | | conflated.cpp:19:19:19:21 | raw | AST only | | conflated.cpp:20:8:20:10 | raw | AST only | +| conflated.cpp:29:3:29:4 | pa | AST only | | conflated.cpp:29:7:29:7 | x | AST only | -| conflated.cpp:30:12:30:12 | pa | IR only | +| conflated.cpp:36:3:36:4 | pa | AST only | | conflated.cpp:36:7:36:7 | x | AST only | -| conflated.cpp:37:12:37:12 | pa | IR only | | conflated.cpp:53:7:53:10 | next | AST only | +| conflated.cpp:54:3:54:4 | ll | AST only | +| conflated.cpp:54:7:54:10 | next | AST only | | conflated.cpp:54:13:54:13 | y | AST only | -| conflated.cpp:55:12:55:15 | ll | IR only | -| conflated.cpp:55:18:55:18 | next | IR only | | conflated.cpp:59:35:59:38 | next | AST only | +| conflated.cpp:60:3:60:4 | ll | AST only | +| conflated.cpp:60:7:60:10 | next | AST only | | conflated.cpp:60:13:60:13 | y | AST only | -| conflated.cpp:61:12:61:15 | ll | IR only | -| conflated.cpp:61:18:61:18 | next | IR only | -| constructors.cpp:18:22:18:23 | this | IR only | -| constructors.cpp:19:22:19:23 | this | IR only | | constructors.cpp:20:24:20:25 | a_ | AST only | | constructors.cpp:21:24:21:25 | b_ | AST only | | constructors.cpp:28:10:28:10 | f | AST only | @@ -287,55 +336,68 @@ | qualifiers.cpp:9:36:9:36 | a | AST only | | qualifiers.cpp:12:56:12:56 | a | AST only | | qualifiers.cpp:13:57:13:57 | a | AST only | -| qualifiers.cpp:18:32:18:36 | this | IR only | | qualifiers.cpp:22:5:22:9 | outer | AST only | +| qualifiers.cpp:22:11:22:18 | call to getInner | AST only | | qualifiers.cpp:22:23:22:23 | a | AST only | +| qualifiers.cpp:23:10:23:14 | outer | AST only | +| qualifiers.cpp:23:16:23:20 | inner | AST only | | qualifiers.cpp:23:23:23:23 | a | AST only | | qualifiers.cpp:27:5:27:9 | outer | AST only | | qualifiers.cpp:27:11:27:18 | call to getInner | AST only | | qualifiers.cpp:27:28:27:37 | call to user_input | AST only | +| qualifiers.cpp:28:10:28:14 | outer | AST only | +| qualifiers.cpp:28:16:28:20 | inner | AST only | | qualifiers.cpp:28:23:28:23 | a | AST only | | qualifiers.cpp:32:17:32:21 | outer | AST only | | qualifiers.cpp:32:23:32:30 | call to getInner | AST only | | qualifiers.cpp:32:35:32:44 | call to user_input | AST only | +| qualifiers.cpp:33:10:33:14 | outer | AST only | +| qualifiers.cpp:33:16:33:20 | inner | AST only | | qualifiers.cpp:33:23:33:23 | a | AST only | | qualifiers.cpp:37:19:37:35 | * ... | AST only | | qualifiers.cpp:37:20:37:24 | outer | AST only | | qualifiers.cpp:37:38:37:47 | call to user_input | AST only | +| qualifiers.cpp:38:10:38:14 | outer | AST only | +| qualifiers.cpp:38:16:38:20 | inner | AST only | | qualifiers.cpp:38:23:38:23 | a | AST only | +| qualifiers.cpp:42:6:42:22 | * ... | AST only | | qualifiers.cpp:42:7:42:11 | outer | AST only | | qualifiers.cpp:42:25:42:25 | a | AST only | +| qualifiers.cpp:43:10:43:14 | outer | AST only | +| qualifiers.cpp:43:16:43:20 | inner | AST only | | qualifiers.cpp:43:23:43:23 | a | AST only | | qualifiers.cpp:47:6:47:11 | & ... | AST only | +| qualifiers.cpp:47:15:47:22 | call to getInner | AST only | | qualifiers.cpp:47:27:47:27 | a | AST only | +| qualifiers.cpp:48:10:48:14 | outer | AST only | +| qualifiers.cpp:48:16:48:20 | inner | AST only | | qualifiers.cpp:48:23:48:23 | a | AST only | | realistic.cpp:26:5:26:10 | offset | AST only | | realistic.cpp:42:20:42:20 | o | AST only | +| realistic.cpp:49:9:49:11 | foo | AST only | | realistic.cpp:49:20:49:22 | baz | AST only | +| realistic.cpp:53:9:53:11 | foo | AST only | +| realistic.cpp:53:9:53:18 | access to array | AST only | +| realistic.cpp:53:20:53:22 | baz | AST only | +| realistic.cpp:53:25:53:33 | userInput | AST only | | realistic.cpp:53:35:53:43 | bufferLen | AST only | +| realistic.cpp:54:16:54:18 | foo | AST only | +| realistic.cpp:54:16:54:25 | access to array | AST only | +| realistic.cpp:54:27:54:29 | baz | AST only | +| realistic.cpp:54:32:54:40 | userInput | AST only | | realistic.cpp:54:42:54:47 | buffer | AST only | -| realistic.cpp:55:16:55:18 | foo | IR only | -| realistic.cpp:55:23:55:25 | access to array | IR only | -| realistic.cpp:55:28:55:36 | baz | IR only | -| realistic.cpp:55:38:55:46 | userInput | IR only | -| realistic.cpp:57:92:57:94 | foo | IR only | -| realistic.cpp:57:99:57:101 | access to array | IR only | -| realistic.cpp:57:104:57:112 | baz | IR only | -| realistic.cpp:57:114:57:122 | userInput | IR only | | realistic.cpp:60:16:60:18 | dst | AST only | -| realistic.cpp:60:25:60:27 | foo | IR only | -| realistic.cpp:60:32:60:34 | access to array | IR only | -| realistic.cpp:60:37:60:45 | baz | IR only | -| realistic.cpp:60:47:60:52 | userInput | IR only | -| realistic.cpp:60:59:60:61 | foo | IR only | -| realistic.cpp:60:66:60:68 | access to array | IR only | -| realistic.cpp:60:71:60:79 | baz | IR only | -| realistic.cpp:60:81:60:89 | userInput | IR only | +| realistic.cpp:61:21:61:23 | foo | AST only | +| realistic.cpp:61:21:61:30 | access to array | AST only | +| realistic.cpp:61:32:61:34 | baz | AST only | +| realistic.cpp:61:37:61:45 | userInput | AST only | | realistic.cpp:61:47:61:55 | bufferLen | AST only | +| realistic.cpp:65:21:65:23 | foo | AST only | +| realistic.cpp:65:21:65:30 | access to array | AST only | +| realistic.cpp:65:32:65:34 | baz | AST only | +| realistic.cpp:65:37:65:45 | userInput | AST only | | realistic.cpp:65:47:65:52 | buffer | AST only | | realistic.cpp:66:21:66:23 | dst | AST only | -| simple.cpp:18:22:18:23 | this | IR only | -| simple.cpp:19:22:19:23 | this | IR only | | simple.cpp:20:24:20:25 | a_ | AST only | | simple.cpp:21:24:21:25 | b_ | AST only | | simple.cpp:28:10:28:10 | f | AST only | @@ -349,24 +411,31 @@ | simple.cpp:51:9:51:9 | h | AST only | | simple.cpp:54:9:54:9 | i | AST only | | simple.cpp:65:7:65:7 | i | AST only | -| simple.cpp:67:13:67:13 | a2 | IR only | -| simple.cpp:79:16:79:17 | this | IR only | -| simple.cpp:79:19:79:20 | f2 | IR only | +| simple.cpp:83:9:83:10 | this | AST only | | simple.cpp:83:12:83:13 | f1 | AST only | | simple.cpp:84:14:84:20 | this | AST only | | simple.cpp:92:7:92:7 | i | AST only | -| simple.cpp:94:13:94:13 | a2 | IR only | -| simple.cpp:104:9:104:9 | i | AST only | -| simple.cpp:106:13:106:13 | b2 | IR only | -| simple.cpp:106:15:106:15 | a | IR only | +| struct_init.c:15:8:15:9 | ab | AST only | | struct_init.c:15:12:15:12 | a | AST only | +| struct_init.c:16:8:16:9 | ab | AST only | | struct_init.c:16:12:16:12 | b | AST only | +| struct_init.c:22:8:22:9 | ab | AST only | | struct_init.c:22:11:22:11 | a | AST only | +| struct_init.c:23:8:23:9 | ab | AST only | | struct_init.c:23:11:23:11 | b | AST only | | struct_init.c:24:10:24:12 | & ... | AST only | +| struct_init.c:31:8:31:12 | outer | AST only | +| struct_init.c:31:14:31:21 | nestedAB | AST only | | struct_init.c:31:23:31:23 | a | AST only | +| struct_init.c:32:8:32:12 | outer | AST only | +| struct_init.c:32:14:32:21 | nestedAB | AST only | | struct_init.c:32:23:32:23 | b | AST only | +| struct_init.c:33:8:33:12 | outer | AST only | +| struct_init.c:33:14:33:22 | pointerAB | AST only | | struct_init.c:33:25:33:25 | a | AST only | +| struct_init.c:34:8:34:12 | outer | AST only | +| struct_init.c:34:14:34:22 | pointerAB | AST only | | struct_init.c:34:25:34:25 | b | AST only | | struct_init.c:36:10:36:24 | & ... | AST only | +| struct_init.c:46:10:46:14 | outer | AST only | | struct_init.c:46:16:46:24 | pointerAB | 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 437a36cc2ba..294c46a5694 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 @@ -1,338 +1,72 @@ | A.cpp:25:7:25:10 | this | | A.cpp:27:22:27:25 | this | -| A.cpp:28:23:28:26 | this | -| A.cpp:49:10:49:10 | b | -| A.cpp:65:10:65:11 | b1 | -| A.cpp:66:10:66:11 | b2 | -| A.cpp:74:10:74:11 | b1 | -| A.cpp:75:10:75:11 | b2 | | A.cpp:100:5:100:6 | c1 | -| A.cpp:107:12:107:13 | c1 | -| A.cpp:120:12:120:13 | c1 | -| A.cpp:132:10:132:10 | b | | A.cpp:142:7:142:7 | b | | A.cpp:143:7:143:10 | this | -| A.cpp:152:10:152:10 | d | -| A.cpp:153:10:153:10 | d | -| A.cpp:153:13:153:13 | b | -| A.cpp:154:10:154:10 | b | -| A.cpp:163:10:163:11 | l3 | -| A.cpp:164:10:164:11 | l3 | -| A.cpp:164:14:164:17 | next | -| A.cpp:165:10:165:11 | l3 | -| A.cpp:165:14:165:17 | next | -| A.cpp:165:20:165:23 | next | -| A.cpp:166:10:166:11 | l3 | -| A.cpp:166:14:166:17 | next | -| A.cpp:166:20:166:23 | next | -| A.cpp:166:26:166:29 | next | -| A.cpp:167:44:167:44 | l | -| A.cpp:169:12:169:12 | l | | A.cpp:183:7:183:10 | this | | A.cpp:184:7:184:10 | this | -| B.cpp:9:10:9:11 | b2 | -| B.cpp:9:14:9:17 | box1 | -| B.cpp:10:10:10:11 | b2 | -| B.cpp:10:14:10:17 | box1 | -| B.cpp:18:10:18:11 | b2 | -| B.cpp:18:14:18:17 | box1 | -| B.cpp:19:10:19:11 | b2 | -| B.cpp:19:14:19:17 | box1 | | B.cpp:35:7:35:10 | this | | B.cpp:36:7:36:10 | this | | B.cpp:46:7:46:10 | this | | C.cpp:24:5:24:8 | this | -| C.cpp:29:10:29:11 | this | -| C.cpp:30:10:30:11 | this | -| C.cpp:31:10:31:11 | this | | D.cpp:9:21:9:24 | this | -| D.cpp:10:30:10:33 | this | | D.cpp:11:29:11:32 | this | | D.cpp:16:21:16:23 | this | -| D.cpp:17:30:17:32 | this | | D.cpp:18:29:18:31 | this | -| D.cpp:30:5:30:5 | b | -| D.cpp:30:8:30:10 | box | -| D.cpp:37:5:37:5 | b | -| D.cpp:44:8:44:14 | call to getBox1 | | D.cpp:57:5:57:12 | this | -| D.cpp:58:5:58:12 | boxfield | -| D.cpp:58:5:58:12 | this | -| D.cpp:58:15:58:17 | box | -| D.cpp:64:10:64:17 | boxfield | -| D.cpp:64:10:64:17 | this | -| D.cpp:64:20:64:22 | box | -| E.cpp:21:10:21:10 | p | -| E.cpp:21:13:21:16 | data | -| E.cpp:29:21:29:21 | b | -| E.cpp:30:21:30:21 | p | -| E.cpp:30:23:30:26 | data | -| E.cpp:32:10:32:10 | b | | aliasing.cpp:9:3:9:3 | s | | aliasing.cpp:13:3:13:3 | s | | aliasing.cpp:17:3:17:3 | s | -| aliasing.cpp:29:8:29:9 | s1 | -| aliasing.cpp:30:8:30:9 | s2 | -| aliasing.cpp:31:8:31:9 | s3 | | aliasing.cpp:37:3:37:6 | ref1 | -| aliasing.cpp:38:8:38:9 | s1 | | aliasing.cpp:42:3:42:4 | s2 | -| aliasing.cpp:43:8:43:11 | ref2 | | aliasing.cpp:49:3:49:7 | copy1 | -| aliasing.cpp:50:8:50:9 | s1 | | aliasing.cpp:54:3:54:4 | s2 | -| aliasing.cpp:55:8:55:12 | copy2 | | aliasing.cpp:60:3:60:4 | s2 | -| aliasing.cpp:62:8:62:12 | copy2 | -| aliasing.cpp:71:9:71:9 | w | | aliasing.cpp:72:3:72:3 | s | -| aliasing.cpp:73:8:73:8 | w | -| aliasing.cpp:73:10:73:10 | s | -| aliasing.cpp:78:11:78:11 | w | | aliasing.cpp:79:3:79:3 | s | -| aliasing.cpp:80:8:80:8 | w | -| aliasing.cpp:80:10:80:10 | s | -| aliasing.cpp:85:10:85:10 | w | | aliasing.cpp:86:3:86:3 | s | -| aliasing.cpp:87:8:87:8 | w | -| aliasing.cpp:87:10:87:10 | s | -| aliasing.cpp:92:3:92:3 | w | | aliasing.cpp:92:5:92:5 | s | -| aliasing.cpp:93:8:93:8 | w | -| aliasing.cpp:93:10:93:10 | s | | aliasing.cpp:98:3:98:3 | s | -| aliasing.cpp:101:14:101:19 | s_copy | | aliasing.cpp:111:16:111:16 | s | -| aliasing.cpp:112:8:112:8 | s | -| aliasing.cpp:141:15:141:15 | s | -| aliasing.cpp:143:8:143:8 | s | | aliasing.cpp:147:16:147:19 | access to array | -| aliasing.cpp:148:8:148:11 | access to array | -| aliasing.cpp:158:15:158:15 | s | -| aliasing.cpp:159:9:159:9 | s | -| aliasing.cpp:164:15:164:15 | s | -| aliasing.cpp:165:8:165:8 | s | -| aliasing.cpp:175:16:175:17 | s2 | | aliasing.cpp:175:19:175:19 | s | -| aliasing.cpp:176:8:176:9 | s2 | -| aliasing.cpp:176:11:176:11 | s | -| aliasing.cpp:181:16:181:17 | s2 | | aliasing.cpp:181:19:181:19 | s | -| aliasing.cpp:182:8:182:9 | s2 | -| aliasing.cpp:182:11:182:11 | s | -| aliasing.cpp:187:16:187:17 | s2 | | aliasing.cpp:187:19:187:19 | s | -| aliasing.cpp:189:8:189:11 | s2_2 | -| aliasing.cpp:189:13:189:13 | s | -| aliasing.cpp:194:16:194:17 | s2 | | aliasing.cpp:194:19:194:19 | s | -| aliasing.cpp:196:8:196:11 | s2_2 | -| aliasing.cpp:196:13:196:13 | s | -| aliasing.cpp:200:16:200:18 | ps2 | | aliasing.cpp:200:21:200:21 | s | -| aliasing.cpp:201:8:201:10 | ps2 | -| aliasing.cpp:201:13:201:13 | s | -| aliasing.cpp:205:16:205:18 | ps2 | | aliasing.cpp:205:21:205:21 | s | -| aliasing.cpp:206:8:206:10 | ps2 | -| aliasing.cpp:206:13:206:13 | s | -| aliasing.cpp:211:3:211:4 | s2 | -| aliasing.cpp:211:6:211:6 | s | -| aliasing.cpp:212:9:212:10 | s2 | -| aliasing.cpp:213:8:213:8 | s | -| aliasing.cpp:218:3:218:4 | s2 | -| aliasing.cpp:218:6:218:6 | s | -| aliasing.cpp:219:9:219:10 | s2 | -| aliasing.cpp:220:8:220:8 | s | -| aliasing.cpp:225:16:225:17 | s2 | -| aliasing.cpp:225:19:225:19 | s | -| aliasing.cpp:226:9:226:10 | s2 | -| aliasing.cpp:227:8:227:8 | s | -| aliasing.cpp:232:16:232:17 | s2 | -| aliasing.cpp:232:19:232:19 | s | -| aliasing.cpp:233:9:233:10 | s2 | -| aliasing.cpp:234:8:234:8 | s | | arrays.cpp:6:3:6:5 | arr | -| arrays.cpp:36:3:36:3 | o | | arrays.cpp:36:3:36:17 | access to array | -| arrays.cpp:36:5:36:10 | nested | -| arrays.cpp:37:8:37:8 | o | -| arrays.cpp:37:8:37:22 | access to array | -| arrays.cpp:37:10:37:15 | nested | -| arrays.cpp:38:8:38:8 | o | -| arrays.cpp:38:8:38:22 | access to array | -| arrays.cpp:38:10:38:15 | nested | -| arrays.cpp:42:3:42:3 | o | -| arrays.cpp:42:3:42:20 | access to array | -| arrays.cpp:42:5:42:12 | indirect | -| arrays.cpp:43:8:43:8 | o | -| arrays.cpp:43:8:43:25 | access to array | -| arrays.cpp:43:10:43:17 | indirect | -| arrays.cpp:44:8:44:8 | o | -| arrays.cpp:44:8:44:25 | access to array | -| arrays.cpp:44:10:44:17 | indirect | -| arrays.cpp:48:3:48:3 | o | -| arrays.cpp:48:3:48:20 | access to array | -| arrays.cpp:48:5:48:12 | indirect | -| arrays.cpp:49:8:49:8 | o | -| arrays.cpp:49:8:49:25 | access to array | -| arrays.cpp:49:10:49:17 | indirect | -| arrays.cpp:50:8:50:8 | o | -| arrays.cpp:50:8:50:25 | access to array | -| arrays.cpp:50:10:50:17 | indirect | | by_reference.cpp:12:5:12:5 | s | | by_reference.cpp:16:5:16:8 | this | -| by_reference.cpp:32:12:32:12 | s | -| by_reference.cpp:36:12:36:15 | this | | by_reference.cpp:84:3:84:7 | inner | | by_reference.cpp:88:3:88:7 | inner | | by_reference.cpp:102:22:102:26 | outer | -| by_reference.cpp:103:21:103:25 | outer | | by_reference.cpp:104:16:104:20 | outer | | by_reference.cpp:106:22:106:27 | pouter | -| by_reference.cpp:107:21:107:26 | pouter | | by_reference.cpp:108:16:108:21 | pouter | -| by_reference.cpp:110:8:110:12 | outer | -| by_reference.cpp:110:14:110:25 | inner_nested | -| by_reference.cpp:111:8:111:12 | outer | -| by_reference.cpp:111:14:111:22 | inner_ptr | -| by_reference.cpp:112:8:112:12 | outer | -| by_reference.cpp:114:8:114:13 | pouter | -| by_reference.cpp:114:16:114:27 | inner_nested | -| by_reference.cpp:115:8:115:13 | pouter | -| by_reference.cpp:115:16:115:24 | inner_ptr | -| by_reference.cpp:116:8:116:13 | pouter | | by_reference.cpp:122:21:122:25 | outer | -| by_reference.cpp:123:22:123:26 | outer | | by_reference.cpp:124:15:124:19 | outer | | by_reference.cpp:126:21:126:26 | pouter | -| by_reference.cpp:127:22:127:27 | pouter | | by_reference.cpp:128:15:128:20 | pouter | -| by_reference.cpp:130:8:130:12 | outer | -| by_reference.cpp:130:14:130:25 | inner_nested | -| by_reference.cpp:131:8:131:12 | outer | -| by_reference.cpp:131:14:131:22 | inner_ptr | -| by_reference.cpp:132:8:132:12 | outer | -| by_reference.cpp:134:8:134:13 | pouter | -| by_reference.cpp:134:16:134:27 | inner_nested | -| by_reference.cpp:135:8:135:13 | pouter | -| by_reference.cpp:135:16:135:24 | inner_ptr | -| by_reference.cpp:136:8:136:13 | pouter | -| complex.cpp:9:20:9:21 | this | -| complex.cpp:10:20:10:21 | this | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | this | -| complex.cpp:42:8:42:8 | b | | complex.cpp:42:10:42:14 | inner | -| complex.cpp:43:8:43:8 | b | | complex.cpp:43:10:43:14 | inner | -| complex.cpp:53:3:53:4 | b1 | | complex.cpp:53:6:53:10 | inner | -| complex.cpp:54:3:54:4 | b2 | | complex.cpp:54:6:54:10 | inner | -| complex.cpp:55:3:55:4 | b3 | | complex.cpp:55:6:55:10 | inner | -| complex.cpp:56:3:56:4 | b3 | | complex.cpp:56:6:56:10 | inner | -| conflated.cpp:10:4:10:5 | ra | -| conflated.cpp:11:9:11:10 | ra | -| conflated.cpp:29:3:29:4 | pa | -| conflated.cpp:30:8:30:9 | pa | -| conflated.cpp:36:3:36:4 | pa | -| conflated.cpp:37:8:37:9 | pa | | conflated.cpp:53:3:53:4 | ll | -| conflated.cpp:54:3:54:4 | ll | -| conflated.cpp:54:7:54:10 | next | -| conflated.cpp:55:8:55:9 | ll | -| conflated.cpp:55:12:55:15 | next | -| conflated.cpp:60:3:60:4 | ll | -| conflated.cpp:60:7:60:10 | next | -| conflated.cpp:61:8:61:9 | ll | -| conflated.cpp:61:12:61:15 | next | -| constructors.cpp:18:22:18:23 | this | -| constructors.cpp:19:22:19:23 | this | | constructors.cpp:20:24:20:25 | this | | constructors.cpp:21:24:21:25 | this | | qualifiers.cpp:9:30:9:33 | this | | qualifiers.cpp:12:49:12:53 | inner | | qualifiers.cpp:13:51:13:55 | inner | -| qualifiers.cpp:18:32:18:36 | this | -| qualifiers.cpp:22:11:22:18 | call to getInner | -| qualifiers.cpp:23:10:23:14 | outer | -| qualifiers.cpp:23:16:23:20 | inner | -| qualifiers.cpp:28:10:28:14 | outer | -| qualifiers.cpp:28:16:28:20 | inner | -| qualifiers.cpp:33:10:33:14 | outer | -| qualifiers.cpp:33:16:33:20 | inner | -| qualifiers.cpp:38:10:38:14 | outer | -| qualifiers.cpp:38:16:38:20 | inner | -| qualifiers.cpp:42:6:42:22 | * ... | -| qualifiers.cpp:43:10:43:14 | outer | -| qualifiers.cpp:43:16:43:20 | inner | -| qualifiers.cpp:47:15:47:22 | call to getInner | -| qualifiers.cpp:48:10:48:14 | outer | -| qualifiers.cpp:48:16:48:20 | inner | -| realistic.cpp:49:9:49:11 | foo | | realistic.cpp:49:9:49:18 | access to array | -| realistic.cpp:53:9:53:11 | foo | -| realistic.cpp:53:9:53:18 | access to array | -| realistic.cpp:53:20:53:22 | baz | -| realistic.cpp:53:25:53:33 | userInput | -| realistic.cpp:54:16:54:18 | foo | -| realistic.cpp:54:16:54:25 | access to array | -| realistic.cpp:54:27:54:29 | baz | -| realistic.cpp:54:32:54:40 | userInput | -| realistic.cpp:55:12:55:14 | foo | -| realistic.cpp:55:12:55:21 | access to array | -| realistic.cpp:55:23:55:25 | baz | -| realistic.cpp:55:28:55:36 | userInput | -| realistic.cpp:57:88:57:90 | foo | -| realistic.cpp:57:88:57:97 | access to array | -| realistic.cpp:57:99:57:101 | baz | -| realistic.cpp:57:104:57:112 | userInput | -| realistic.cpp:60:21:60:23 | foo | -| realistic.cpp:60:21:60:30 | access to array | -| realistic.cpp:60:32:60:34 | baz | -| realistic.cpp:60:37:60:45 | userInput | -| realistic.cpp:60:55:60:57 | foo | -| realistic.cpp:60:55:60:64 | access to array | -| realistic.cpp:60:66:60:68 | baz | -| realistic.cpp:60:71:60:79 | userInput | -| realistic.cpp:61:21:61:23 | foo | -| realistic.cpp:61:21:61:30 | access to array | -| realistic.cpp:61:32:61:34 | baz | -| realistic.cpp:61:37:61:45 | userInput | -| realistic.cpp:65:21:65:23 | foo | -| realistic.cpp:65:21:65:30 | access to array | -| realistic.cpp:65:32:65:34 | baz | -| realistic.cpp:65:37:65:45 | userInput | -| simple.cpp:18:22:18:23 | this | -| simple.cpp:19:22:19:23 | this | | simple.cpp:20:24:20:25 | this | | simple.cpp:21:24:21:25 | this | | simple.cpp:65:5:65:5 | a | -| simple.cpp:67:10:67:11 | a2 | -| simple.cpp:79:16:79:17 | f2 | -| simple.cpp:79:16:79:17 | this | | simple.cpp:83:9:83:10 | f2 | -| simple.cpp:83:9:83:10 | this | | simple.cpp:92:5:92:5 | a | -| simple.cpp:94:10:94:11 | a2 | -| simple.cpp:104:5:104:5 | b | -| simple.cpp:104:7:104:7 | a | -| simple.cpp:106:10:106:11 | b2 | -| simple.cpp:106:13:106:13 | a | -| struct_init.c:15:8:15:9 | ab | -| struct_init.c:16:8:16:9 | ab | -| struct_init.c:22:8:22:9 | ab | -| struct_init.c:23:8:23:9 | ab | -| struct_init.c:31:8:31:12 | outer | -| struct_init.c:31:14:31:21 | nestedAB | -| struct_init.c:32:8:32:12 | outer | -| struct_init.c:32:14:32:21 | nestedAB | -| struct_init.c:33:8:33:12 | outer | -| struct_init.c:33:14:33:22 | pointerAB | -| struct_init.c:34:8:34:12 | outer | -| struct_init.c:34:14:34:22 | pointerAB | | struct_init.c:36:11:36:15 | outer | -| struct_init.c:46:10:46:14 | outer | 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 9821d527b87..9b03e4f8039 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/partial-definition.expected @@ -220,18 +220,6 @@ | aliasing.cpp:205:15:205:24 | & ... | | aliasing.cpp:205:16:205:18 | ps2 | | aliasing.cpp:205:21:205:21 | s | -| aliasing.cpp:211:3:211:4 | s2 | -| aliasing.cpp:211:6:211:6 | s | -| aliasing.cpp:211:8:211:9 | m1 | -| aliasing.cpp:218:3:218:4 | s2 | -| aliasing.cpp:218:6:218:6 | s | -| aliasing.cpp:218:8:218:9 | m1 | -| aliasing.cpp:225:15:225:22 | & ... | -| aliasing.cpp:225:16:225:17 | s2 | -| aliasing.cpp:225:19:225:19 | s | -| aliasing.cpp:232:15:232:22 | & ... | -| aliasing.cpp:232:16:232:17 | s2 | -| aliasing.cpp:232:19:232:19 | s | | arrays.cpp:6:3:6:8 | access to array | | arrays.cpp:15:3:15:10 | * ... | | arrays.cpp:36:3:36:3 | o | @@ -352,8 +340,6 @@ | by_reference.cpp:135:27:135:27 | a | | by_reference.cpp:136:8:136:13 | pouter | | by_reference.cpp:136:16:136:16 | a | -| by_reference.cpp:140:3:140:5 | * ... | -| by_reference.cpp:145:15:145:16 | & ... | | complex.cpp:11:22:11:23 | a_ | | complex.cpp:11:22:11:23 | this | | complex.cpp:12:22:12:23 | b_ | @@ -498,9 +484,6 @@ | simple.cpp:84:14:84:20 | this | | simple.cpp:92:5:92:5 | a | | simple.cpp:92:7:92:7 | i | -| simple.cpp:104:5:104:5 | b | -| simple.cpp:104:7:104:7 | a | -| simple.cpp:104:9:104:9 | i | | struct_init.c:15:8:15:9 | ab | | struct_init.c:15:12:15:12 | a | | struct_init.c:16:8:16:9 | ab | 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 6ea374d0ddf..6604dde87d4 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/path-flow.expected @@ -160,7 +160,6 @@ edges | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:175:15:175:22 | ref arg & ... | | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:187:15:187:22 | ref arg & ... | | aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:200:15:200:24 | ref arg & ... | -| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:225:15:225:22 | ref arg & ... | | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:4:106:5 | pa [inner post update] | | aliasing.cpp:158:15:158:15 | s [post update] [data] | aliasing.cpp:159:9:159:9 | s [data] | | aliasing.cpp:158:17:158:20 | ref arg data | aliasing.cpp:158:15:158:15 | s [post update] [data] | @@ -188,20 +187,6 @@ edges | aliasing.cpp:200:23:200:24 | m1 [inner post update] | aliasing.cpp:200:21:200:21 | s [post update] [m1] | | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | aliasing.cpp:201:13:201:13 | s [m1] | | aliasing.cpp:201:13:201:13 | s [m1] | aliasing.cpp:201:15:201:16 | m1 | -| aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | aliasing.cpp:212:9:212:10 | s2 [s, m1] | -| aliasing.cpp:211:3:211:24 | ... = ... | aliasing.cpp:211:6:211:6 | s [post update] [m1] | -| aliasing.cpp:211:6:211:6 | s [post update] [m1] | aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:211:3:211:24 | ... = ... | -| aliasing.cpp:212:9:212:10 | s2 [s, m1] | aliasing.cpp:212:12:212:12 | s [m1] | -| aliasing.cpp:212:12:212:12 | s [m1] | aliasing.cpp:213:8:213:8 | s [m1] | -| aliasing.cpp:213:8:213:8 | s [m1] | aliasing.cpp:213:10:213:11 | m1 | -| aliasing.cpp:225:15:225:22 | ref arg & ... | aliasing.cpp:225:21:225:22 | m1 [inner post update] | -| aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | aliasing.cpp:226:9:226:10 | s2 [s, m1] | -| aliasing.cpp:225:19:225:19 | s [post update] [m1] | aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | -| aliasing.cpp:225:21:225:22 | m1 [inner post update] | aliasing.cpp:225:19:225:19 | s [post update] [m1] | -| aliasing.cpp:226:9:226:10 | s2 [s, m1] | aliasing.cpp:226:12:226:12 | s [m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | aliasing.cpp:227:8:227:8 | s [m1] | -| aliasing.cpp:227:8:227:8 | s [m1] | aliasing.cpp:227:10:227:11 | m1 | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | @@ -323,9 +308,6 @@ 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 | -| by_reference.cpp:140:4:140:5 | pa [inner post update] | by_reference.cpp:145:15:145:16 | ref arg & ... | -| by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:140:4:140:5 | pa [inner post update] | -| by_reference.cpp:145:15:145:16 | ref arg & ... | by_reference.cpp:146:8:146:8 | s | | complex.cpp:40:17:40:17 | b [inner, f, a_] | complex.cpp:42:8:42:8 | b [inner, f, a_] | | complex.cpp:40:17:40:17 | b [inner, f, b_] | complex.cpp:43:8:43:8 | b [inner, f, b_] | | complex.cpp:42:8:42:8 | b [inner, f, a_] | complex.cpp:42:10:42:14 | inner [f, a_] | @@ -467,12 +449,6 @@ edges | simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] | | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | | simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i | -| simple.cpp:104:5:104:5 | b [post update] [a, i] | simple.cpp:106:10:106:11 | b2 [a, i] | -| simple.cpp:104:5:104:24 | ... = ... | simple.cpp:104:7:104:7 | a [post update] [i] | -| simple.cpp:104:7:104:7 | a [post update] [i] | simple.cpp:104:5:104:5 | b [post update] [a, i] | -| simple.cpp:104:13:104:22 | call to user_input | simple.cpp:104:5:104:24 | ... = ... | -| simple.cpp:106:10:106:11 | b2 [a, i] | simple.cpp:106:13:106:13 | a [i] | -| simple.cpp:106:13:106:13 | a [i] | simple.cpp:106:15:106:15 | i | | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] | @@ -713,22 +689,6 @@ nodes | aliasing.cpp:201:8:201:10 | ps2 [s, m1] | semmle.label | ps2 [s, m1] | | aliasing.cpp:201:13:201:13 | s [m1] | semmle.label | s [m1] | | aliasing.cpp:201:15:201:16 | m1 | semmle.label | m1 | -| aliasing.cpp:211:3:211:4 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | -| aliasing.cpp:211:3:211:24 | ... = ... | semmle.label | ... = ... | -| aliasing.cpp:211:6:211:6 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:211:13:211:22 | call to user_input | semmle.label | call to user_input | -| aliasing.cpp:212:9:212:10 | s2 [s, m1] | semmle.label | s2 [s, m1] | -| aliasing.cpp:212:12:212:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:213:8:213:8 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:213:10:213:11 | m1 | semmle.label | m1 | -| aliasing.cpp:225:15:225:22 | ref arg & ... | semmle.label | ref arg & ... | -| aliasing.cpp:225:16:225:17 | s2 [post update] [s, m1] | semmle.label | s2 [post update] [s, m1] | -| aliasing.cpp:225:19:225:19 | s [post update] [m1] | semmle.label | s [post update] [m1] | -| aliasing.cpp:225:21:225:22 | m1 [inner post update] | semmle.label | m1 [inner post update] | -| aliasing.cpp:226:9:226:10 | s2 [s, m1] | semmle.label | s2 [s, m1] | -| aliasing.cpp:226:12:226:12 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:227:8:227:8 | s [m1] | semmle.label | s [m1] | -| aliasing.cpp:227:10:227:11 | m1 | semmle.label | m1 | | arrays.cpp:6:12:6:21 | call to user_input | semmle.label | call to user_input | | arrays.cpp:7:8:7:13 | access to array | semmle.label | access to array | | arrays.cpp:8:8:8:13 | access to array | semmle.label | access to array | @@ -858,10 +818,6 @@ 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 | -| by_reference.cpp:140:4:140:5 | pa [inner post update] | semmle.label | pa [inner post update] | -| by_reference.cpp:140:16:140:25 | call to user_input | semmle.label | call to user_input | -| by_reference.cpp:145:15:145:16 | ref arg & ... | semmle.label | ref arg & ... | -| by_reference.cpp:146:8:146:8 | s | semmle.label | s | | complex.cpp:40:17:40:17 | b [inner, f, a_] | semmle.label | b [inner, f, a_] | | complex.cpp:40:17:40:17 | b [inner, f, b_] | semmle.label | b [inner, f, b_] | | complex.cpp:42:8:42:8 | b [inner, f, a_] | semmle.label | b [inner, f, a_] | @@ -1024,13 +980,6 @@ nodes | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | -| simple.cpp:104:5:104:5 | b [post update] [a, i] | semmle.label | b [post update] [a, i] | -| simple.cpp:104:5:104:24 | ... = ... | semmle.label | ... = ... | -| simple.cpp:104:7:104:7 | a [post update] [i] | semmle.label | a [post update] [i] | -| simple.cpp:104:13:104:22 | call to user_input | semmle.label | call to user_input | -| simple.cpp:106:10:106:11 | b2 [a, i] | semmle.label | b2 [a, i] | -| simple.cpp:106:13:106:13 | a [i] | semmle.label | a [i] | -| simple.cpp:106:15:106:15 | i | semmle.label | i | | struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -1096,8 +1045,6 @@ nodes | aliasing.cpp:176:13:176:14 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:176:13:176:14 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:189:15:189:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:189:15:189:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | aliasing.cpp:201:15:201:16 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:201:15:201:16 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | -| aliasing.cpp:213:10:213:11 | m1 | aliasing.cpp:211:13:211:22 | call to user_input | aliasing.cpp:213:10:213:11 | m1 | m1 flows from $@ | aliasing.cpp:211:13:211:22 | call to user_input | call to user_input | -| aliasing.cpp:227:10:227:11 | m1 | aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:227:10:227:11 | m1 | m1 flows from $@ | aliasing.cpp:106:9:106:18 | call to user_input | call to user_input | | arrays.cpp:7:8:7:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:8:8:8:13 | access to array | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array | access to array flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | | arrays.cpp:9:8:9:11 | * ... | arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... | * ... flows from $@ | arrays.cpp:6:12:6:21 | call to user_input | call to user_input | @@ -1124,7 +1071,6 @@ nodes | 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 | -| by_reference.cpp:146:8:146:8 | s | by_reference.cpp:140:16:140:25 | call to user_input | by_reference.cpp:146:8:146:8 | s | s flows from $@ | by_reference.cpp:140:16:140:25 | 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 | @@ -1152,7 +1098,6 @@ nodes | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | -| simple.cpp:106:15:106:15 | i | simple.cpp:104:13:104:22 | call to user_input | simple.cpp:106:15:106:15 | i | i flows from $@ | simple.cpp:104:13:104:22 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index 829974a1b67..e4d4f70edb0 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -94,16 +94,4 @@ void single_field_test_typedef(A_typedef a) sink(a2.i); //$ ast,ir } -struct B { - A a; -}; - -void single_field_test_depth_2() -{ - B b; - b.a.i = user_input(); - B b2 = b; - sink(b2.a.i); //$ ast MISSING: ir -} - } // namespace Simple diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected index 4f709d960cc..6aeadb2f174 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected @@ -1464,93 +1464,117 @@ unreachableNodeCCtx localCallNodes postIsNotPre postHasUniquePre -| allocators.cpp:16:14:16:36 | Foo output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:16:19:16:20 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:26:23:26:24 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:41:22:41:23 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:48:22:48:24 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:48:34:48:36 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| condition_decls.cpp:48:52:48:53 | BoxedInt output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:30:9:30:13 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:30:18:30:22 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:33:9:33:13 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:33:18:33:22 | C1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:39:9:39:13 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:39:18:39:22 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:42:9:42:13 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| conditional_destructors.cpp:42:18:42:22 | C2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| constructorinitializer.cpp:8:6:8:18 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:77:19:77:21 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:11:82:14 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:17:82:55 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:45:82:48 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:82:51:82:51 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:88:25:88:30 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp11.cpp:88:33:88:38 | Val output argument | PostUpdateNode should have one pre-update node but has 0. | -| cpp17.cpp:15:5:15:45 | HasTwoArgCtor output argument | PostUpdateNode should have one pre-update node but has 0. | -| destructors.cpp:50:9:50:13 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| destructors.cpp:51:36:51:38 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| file://:0:0:0:0 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:616:12:616:13 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:617:15:617:22 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:619:16:619:30 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:662:9:662:19 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:663:5:663:5 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:736:5:736:19 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:745:8:745:8 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:748:10:748:10 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:757:12:757:12 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:757:12:757:12 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:766:13:766:13 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:766:13:766:13 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:775:15:775:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:775:15:775:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:784:15:784:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:784:15:784:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | MiddleVB1 output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | MiddleVB2 output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:793:15:793:15 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:800:8:800:8 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:801:10:801:10 | Middle output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:802:11:802:11 | Derived output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:809:7:809:13 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:810:7:810:26 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:823:7:823:13 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:824:7:824:26 | Base output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:846:8:846:8 | PolymorphicBase output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:850:19:850:19 | PolymorphicBase output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:851:22:851:22 | PolymorphicDerived output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:868:3:868:12 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:944:3:944:14 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ir.cpp:945:3:945:27 | String output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_assume.cpp:28:18:28:23 | fgets output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_try_mix.cpp:11:12:11:15 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_try_mix.cpp:28:12:28:15 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ms_try_mix.cpp:48:10:48:13 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| newexpr.cpp:8:2:8:20 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| ops.cpp:26:31:26:53 | C_with_constr_destr output argument | PostUpdateNode should have one pre-update node but has 0. | -| parameterinitializer.cpp:25:5:25:8 | c output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:31:10:31:11 | MyClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:236:7:236:7 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:240:7:240:7 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:249:21:249:23 | MyConstructorClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:250:17:250:19 | MyDerivedClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| static_init_templates.cpp:251:20:251:23 | MyContainingClass output argument | PostUpdateNode should have one pre-update node but has 0. | -| stmt_expr.cpp:13:18:13:19 | C output argument | PostUpdateNode should have one pre-update node but has 0. | -| try_catch.cpp:7:8:7:8 | exception output argument | PostUpdateNode should have one pre-update node but has 0. | -| try_catch.cpp:7:8:7:8 | exception output argument | PostUpdateNode should have one pre-update node but has 0. | -| try_catch.cpp:13:5:13:16 | exn1 output argument | PostUpdateNode should have one pre-update node but has 0. | +| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should have one pre-update node but has 0. | +| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should have one pre-update node but has 0. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should have one pre-update node but has 0. | +| ir.cpp:531:14:531:14 | Store | PostUpdateNode should have one pre-update node but has 0. | uniquePostUpdate postIsInSameCallable reverseRead argHasPostUpdate postWithInFlow -| cpp11.cpp:77:19:77:21 | Val output argument | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:11:82:14 | Val output argument | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:45:82:48 | Val output argument | PostUpdateNode should not be the target of local flow. | -| cpp11.cpp:82:51:82:51 | Val output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:809:7:809:13 | Base output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:810:7:810:26 | Base output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:823:7:823:13 | Base output argument | PostUpdateNode should not be the target of local flow. | -| ir.cpp:824:7:824:26 | Base output argument | PostUpdateNode should not be the target of local flow. | +| aggregateinitializer.c:3:14:3:18 | Chi | PostUpdateNode should not be the target of local flow. | +| aggregateinitializer.c:3:21:3:25 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:3:27:3:27 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:3:35:3:35 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:11:4:23 | Chi | PostUpdateNode should not be the target of local flow. | +| allocators.cpp:4:17:4:23 | Chi | PostUpdateNode should not be the target of local flow. | +| assignexpr.cpp:9:2:9:12 | Store | PostUpdateNode should not be the target of local flow. | +| bad_asts.cpp:15:10:15:12 | Store | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:26:14:26 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:29:14:29 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:32:14:32 | Chi | PostUpdateNode should not be the target of local flow. | +| builtin.c:14:35:14:35 | Chi | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:5:3:22 | Chi | PostUpdateNode should not be the target of local flow. | +| condition_decls.cpp:3:21:3:21 | Chi | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:6:13:6:19 | Chi | PostUpdateNode should not be the target of local flow. | +| conditional_destructors.cpp:18:13:18:19 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:65:19:65:45 | Store | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:17:82:55 | Chi | PostUpdateNode should not be the target of local flow. | +| cpp11.cpp:82:45:82:48 | Chi | PostUpdateNode should not be the target of local flow. | +| defdestructordeleteexpr.cpp:4:9:4:15 | Chi | PostUpdateNode should not be the target of local flow. | +| deleteexpr.cpp:7:9:7:15 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:177:5:177:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:178:5:178:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:183:5:183:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:184:5:184:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:342:5:342:10 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:428:5:428:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:429:5:429:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:504:19:504:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:504:22:504:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:505:16:505:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:505:19:505:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:506:16:506:18 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:513:14:513:16 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:14:514:26 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:19:514:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:514:22:514:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:19:515:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:22:515:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:29:515:29 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:515:32:515:32 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:17:516:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:19:516:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:24:516:28 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:516:26:516:26 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:19:521:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:22:521:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:521:25:521:25 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:522:16:522:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:522:19:522:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:531:14:531:14 | Store | PostUpdateNode should not be the target of local flow. | +| ir.cpp:577:16:577:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:577:19:577:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:578:19:578:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:578:22:578:22 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:579:16:579:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:579:19:579:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:643:9:643:21 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:644:9:644:23 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:645:9:645:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:659:9:659:14 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:660:13:660:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:661:9:661:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:662:9:662:19 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:663:5:663:5 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:745:8:745:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:745:8:745:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:748:10:748:10 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:754:8:754:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:757:12:757:12 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:763:8:763:8 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:766:13:766:13 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:775:15:775:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:784:15:784:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:793:15:793:15 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:943:3:943:11 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:947:3:947:25 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:17:962:47 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:26:962:30 | Chi | PostUpdateNode should not be the target of local flow. | +| ir.cpp:962:41:962:45 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:130:5:130:11 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:131:5:131:13 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:32:154:32 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:35:154:35 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:40:154:40 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:154:43:154:43 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:157:14:157:18 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:158:14:158:18 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:160:31:160:33 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:220:3:223:3 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:221:10:221:10 | Chi | PostUpdateNode should not be the target of local flow. | +| misc.c:222:10:222:10 | Chi | PostUpdateNode should not be the target of local flow. | +| range_analysis.c:102:5:102:15 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:3:2:3:8 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:21:2:21:12 | Chi | PostUpdateNode should not be the target of local flow. | +| static_init_templates.cpp:240:7:240:7 | Chi | PostUpdateNode should not be the target of local flow. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected index 0299afff063..9876b9695ad 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/TaintedAllocationSize/TaintedAllocationSize.expected @@ -59,21 +59,18 @@ edges | test.cpp:227:24:227:37 | (const char *)... | test.cpp:229:9:229:18 | local_size | | test.cpp:241:2:241:32 | Chi [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | | test.cpp:241:2:241:32 | Chi [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:241:2:241:32 | Chi [array content] | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:279:17:279:20 | get_size output argument [array content] | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | test.cpp:295:18:295:21 | get_size output argument [array content] | -| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | -| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | +| test.cpp:241:18:241:23 | call to getenv | test.cpp:241:2:241:32 | Chi [array content] | +| test.cpp:241:18:241:31 | (const char *)... | test.cpp:241:2:241:32 | Chi [array content] | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:25 | call to getenv | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | | test.cpp:249:20:249:33 | (const char *)... | test.cpp:253:11:253:29 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | test.cpp:281:11:281:28 | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | get_size output argument | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | test.cpp:298:10:298:27 | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | get_size output argument | +| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | Chi | test.cpp:281:11:281:28 | ... * ... | +| test.cpp:279:17:279:20 | get_size output argument [array content] | test.cpp:279:17:279:20 | Chi | +| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | Chi | test.cpp:298:10:298:27 | ... * ... | +| test.cpp:295:18:295:21 | get_size output argument [array content] | test.cpp:295:18:295:21 | Chi | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:24 | call to getenv | test.cpp:305:11:305:28 | ... * ... | | test.cpp:301:19:301:32 | (const char *)... | test.cpp:305:11:305:28 | ... * ... | @@ -147,7 +144,6 @@ nodes | test.cpp:237:2:237:8 | Argument 0 | semmle.label | Argument 0 | | test.cpp:241:2:241:32 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:241:2:241:32 | ChiPartial | semmle.label | ChiPartial | -| test.cpp:241:2:241:32 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:241:18:241:23 | call to getenv | semmle.label | call to getenv | | test.cpp:241:18:241:31 | (const char *)... | semmle.label | (const char *)... | | test.cpp:249:20:249:25 | call to getenv | semmle.label | call to getenv | @@ -155,12 +151,12 @@ nodes | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | | test.cpp:253:11:253:29 | ... * ... | semmle.label | ... * ... | -| test.cpp:279:17:279:20 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:279:17:279:20 | Chi | semmle.label | Chi | | test.cpp:279:17:279:20 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | | test.cpp:281:11:281:28 | ... * ... | semmle.label | ... * ... | -| test.cpp:295:18:295:21 | get_size output argument | semmle.label | get_size output argument | +| test.cpp:295:18:295:21 | Chi | semmle.label | Chi | | test.cpp:295:18:295:21 | get_size output argument [array content] | semmle.label | get_size output argument [array content] | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | | test.cpp:298:10:298:27 | ... * ... | semmle.label | ... * ... | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected index c684f1da6ce..ca8dd38fc3b 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/uncontrolled/ArithmeticUncontrolled.expected @@ -43,23 +43,19 @@ edges | test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | | test.cpp:8:9:8:12 | call to rand | test.cpp:8:9:8:12 | Store | | test.cpp:13:2:13:15 | Chi [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | -| test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | test.cpp:13:2:13:15 | Chi [array content] | -| test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | -| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] | +| test.cpp:13:10:13:13 | call to rand | test.cpp:13:2:13:15 | Chi [array content] | | test.cpp:18:2:18:14 | Chi [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | -| test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | test.cpp:18:2:18:14 | Chi [array content] | -| test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | -| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] | +| test.cpp:18:9:18:12 | call to rand | test.cpp:18:2:18:14 | Chi [array content] | | test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | | test.cpp:24:11:24:18 | call to get_rand | test.cpp:25:7:25:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | test.cpp:31:7:31:7 | r | -| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | get_rand2 output argument | -| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | test.cpp:37:7:37:7 | r | -| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | get_rand3 output argument | +| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | Chi | test.cpp:31:7:31:7 | r | +| test.cpp:30:13:30:14 | get_rand2 output argument [array content] | test.cpp:30:13:30:14 | Chi | +| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | Chi | test.cpp:37:7:37:7 | r | +| test.cpp:36:13:36:13 | get_rand3 output argument [array content] | test.cpp:36:13:36:13 | Chi | nodes | test.c:18:13:18:16 | call to rand | semmle.label | call to rand | | test.c:18:13:18:16 | call to rand | semmle.label | call to rand | @@ -114,24 +110,22 @@ nodes | test.cpp:8:9:8:12 | call to rand | semmle.label | call to rand | | test.cpp:13:2:13:15 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:13:2:13:15 | ChiPartial | semmle.label | ChiPartial | -| test.cpp:13:2:13:15 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | | test.cpp:13:10:13:13 | call to rand | semmle.label | call to rand | | test.cpp:18:2:18:14 | Chi [array content] | semmle.label | Chi [array content] | | test.cpp:18:2:18:14 | ChiPartial | semmle.label | ChiPartial | -| test.cpp:18:2:18:14 | ChiTotal [post update] [array content] | semmle.label | ChiTotal [post update] [array content] | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | test.cpp:18:9:18:12 | call to rand | semmle.label | call to rand | | test.cpp:24:11:24:18 | call to get_rand | semmle.label | call to get_rand | | test.cpp:25:7:25:7 | r | semmle.label | r | | test.cpp:25:7:25:7 | r | semmle.label | r | | test.cpp:25:7:25:7 | r | semmle.label | r | -| test.cpp:30:13:30:14 | get_rand2 output argument | semmle.label | get_rand2 output argument | +| test.cpp:30:13:30:14 | Chi | semmle.label | Chi | | test.cpp:30:13:30:14 | get_rand2 output argument [array content] | semmle.label | get_rand2 output argument [array content] | | test.cpp:31:7:31:7 | r | semmle.label | r | | test.cpp:31:7:31:7 | r | semmle.label | r | | test.cpp:31:7:31:7 | r | semmle.label | r | -| test.cpp:36:13:36:13 | get_rand3 output argument | semmle.label | get_rand3 output argument | +| test.cpp:36:13:36:13 | Chi | semmle.label | Chi | | test.cpp:36:13:36:13 | get_rand3 output argument [array content] | semmle.label | get_rand3 output argument [array content] | | test.cpp:37:7:37:7 | r | semmle.label | r | | test.cpp:37:7:37:7 | r | semmle.label | r | From 691a316460622fbd4d9e2b2af42d0128b0a38687 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 3 Feb 2021 09:07:27 +0100 Subject: [PATCH 082/429] C++: Add tests to cpp/unsigned-difference-expression-compared-zero and remove a couple of classes of FPs. --- ...nsignedDifferenceExpressionComparedZero.ql | 19 ++++- ...dDifferenceExpressionComparedZero.expected | 10 +++ ...gnedDifferenceExpressionComparedZero.qlref | 1 + .../test.cpp | 77 +++++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref create mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql index 300b2f944b5..7b110ec24db 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -13,11 +13,28 @@ import cpp import semmle.code.cpp.commons.Exclusions +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.controlflow.Guards + +/** Holds if `sub` will never be nonnegative. */ +predicate nonNegative(SubExpr sub) { + not exprMightOverflowNegatively(sub.getFullyConverted()) + or + // The subtraction is guarded by a check of the form `left >= right`. + exists(GuardCondition guard, Expr left, Expr right | + left = globalValueNumber(sub.getLeftOperand()).getAnExpr() and + right = globalValueNumber(sub.getRightOperand()).getAnExpr() and + guard.controls(sub.getBasicBlock(), true) and + guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false) + ) +} from RelationalOperation ro, SubExpr sub where not isFromMacroDefinition(ro) and ro.getLesserOperand().getValue().toInt() = 0 and ro.getGreaterOperand() = sub and - sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() + sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() and + not nonNegative(sub) select ro, "Difference in condition is always greater than or equal to zero" diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected new file mode 100644 index 00000000000..6e1b80a4c8c --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected @@ -0,0 +1,10 @@ +| test.cpp:6:5:6:13 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:10:8:10:24 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:15:9:15:25 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:32:12:32:20 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:39:12:39:20 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:47:5:47:13 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:55:5:55:13 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:62:5:62:13 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:69:5:69:13 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:75:8:75:16 | ... > ... | Difference in condition is always greater than or equal to zero | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref new file mode 100644 index 00000000000..2d15983a540 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp new file mode 100644 index 00000000000..11de69e8c62 --- /dev/null +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp @@ -0,0 +1,77 @@ +int getAnInt(); + +bool cond(); + +void test(unsigned x, unsigned y, bool unknown) { + if(x - y > 0) { } // BAD + + unsigned total = getAnInt(); + unsigned limit = getAnInt(); + while(limit - total > 0) { // BAD + total += getAnInt(); + } + + if(total <= limit) { + while(limit - total > 0) { // GOOD [FALSE POSITIVE] + total += getAnInt(); + if(total > limit) break; + } + } + + if(x >= y) { + bool b = x - y > 0; // GOOD + } + + if((int)(x - y) >= 0) { } // GOOD. Maybe an overflow happened, but the result is converted to the "likely intended" result before the comparison + + if(unknown) { + y = x & 0xFF; + } else { + y = x; + } + bool b1 = x - y > 0; // GOOD [FALSE POSITIVE] + + x = getAnInt(); + y = getAnInt(); + if(y > x) { + y = x - 1; + } + bool b2 = x - y > 0; // GOOD [FALSE POSITIVE] + + int N = getAnInt(); + y = x; + while(cond()) { + if(unknown) { y--; } + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + x = y; + while(cond()) { + if(unknown) break; + y--; + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + y = 0; + for(int i = 0; i < x; ++i) { + if(unknown) { ++y; } + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + x = y; + while(cond()) { + if(unknown) { x++; } + } + + if(x - y > 0) { } // GOOD [FALSE POSITIVE] + + int n = getAnInt(); + if (n > x - y) { n = x - y; } + if (n > 0) { + y += n; // NOTE: `n` is at most `x - y` at this point. + if (x - y > 0) {} // GOOD [FALSE POSITIVE] + } +} \ No newline at end of file From 12ee49748545effc470898a36101b2caf3882973 Mon Sep 17 00:00:00 2001 From: CaptainFreak Date: Wed, 3 Feb 2021 15:48:02 +0530 Subject: [PATCH 083/429] move query to src, rename and refactor --- .../CWE-073/TemplateObjectInjection.ql} | 21 +++++++------------ .../TemplateObjectInjection.js} | 0 .../TemplateObjectInjection_fixed.js} | 0 3 files changed, 8 insertions(+), 13 deletions(-) rename javascript/ql/{test/experimental/Security/CWE-073/ExpressHbsLFR.ql => src/experimental/Security/CWE-073/TemplateObjectInjection.ql} (55%) rename javascript/ql/{test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js => src/experimental/Security/CWE-073/documentation-examples/TemplateObjectInjection.js} (100%) rename javascript/ql/{test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js => src/experimental/Security/CWE-073/documentation-examples/TemplateObjectInjection_fixed.js} (100%) diff --git a/javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql similarity index 55% rename from javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql rename to javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql index de66932a7af..b1074ab618f 100644 --- a/javascript/ql/test/experimental/Security/CWE-073/ExpressHbsLFR.ql +++ b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql @@ -1,10 +1,10 @@ /** - * @name Express-Hbs Local File Read and Potential RCE - * @description Writing user input directly to res.render of ExpressJS used with Hbs can lead to LFR + * @name Template Object Injection + * @description Instantiating a template using a user-controlled object is vulnerable to local file read and potential remote code execution. * @kind path-problem * @problem.severity error * @precision high - * @id js/express-hbs-lfr + * @id js/template-object-injection * @tags security * external/cwe/cwe-073 * external/cwe/cwe-094 @@ -13,15 +13,9 @@ import javascript import DataFlow import PathGraph -import Express -import semmle.javascript.DynamicPropertyAccess predicate isUsingHbsEngine() { - exists(MethodCallExpr method | - method.getMethodName() = "set" and - Express::appCreation().flowsToExpr(method.getReceiver()) and - method.getArgument(1).getStringValue().matches("hbs") - ) + Express::appCreation().getAMethodCall("set").getArgument(1).mayHaveStringValue("hbs") } class HbsLFRTaint extends TaintTracking::Configuration { @@ -39,6 +33,7 @@ class HbsLFRTaint extends TaintTracking::Configuration { } } -from HbsLFRTaint cfg, Node source, Node sink -where cfg.hasFlow(source, sink) -select source, sink +from HbsLFRTaint cfg, PathNode source, PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Template object injection due to $@.", source.getNode(), + "user-provided value" diff --git a/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js b/javascript/ql/src/experimental/Security/CWE-073/documentation-examples/TemplateObjectInjection.js similarity index 100% rename from javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR.js rename to javascript/ql/src/experimental/Security/CWE-073/documentation-examples/TemplateObjectInjection.js diff --git a/javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js b/javascript/ql/src/experimental/Security/CWE-073/documentation-examples/TemplateObjectInjection_fixed.js similarity index 100% rename from javascript/ql/test/experimental/Security/CWE-073/documentation-examples/ExpressHbsLFR_fixed.js rename to javascript/ql/src/experimental/Security/CWE-073/documentation-examples/TemplateObjectInjection_fixed.js From c6a22844e2e781f766ebe747f89e701b966f67c3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 12:16:57 +0100 Subject: [PATCH 084/429] add test for `js/template-object-injection` --- .../CWE-073/TemplateObjectInjection.expected | 37 +++++++++++++++++++ .../CWE-073/TemplateObjectInjection.qlref | 1 + .../test/experimental/Security/CWE-073/tst.js | 17 +++++++++ 3 files changed, 55 insertions(+) create mode 100644 javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected create mode 100644 javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.qlref create mode 100644 javascript/ql/test/experimental/Security/CWE-073/tst.js diff --git a/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected b/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected new file mode 100644 index 00000000000..455498d5d58 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected @@ -0,0 +1,37 @@ +nodes +| tst.js:5:9:5:46 | bodyParameter | +| tst.js:5:25:5:32 | req.body | +| tst.js:5:25:5:32 | req.body | +| tst.js:5:25:5:46 | req.bod ... rameter | +| tst.js:6:9:6:49 | queryParameter | +| tst.js:6:26:6:49 | req.que ... rameter | +| tst.js:6:26:6:49 | req.que ... rameter | +| tst.js:8:28:8:40 | bodyParameter | +| tst.js:8:28:8:40 | bodyParameter | +| tst.js:9:28:9:41 | queryParameter | +| tst.js:9:28:9:41 | queryParameter | +| tst.js:12:32:12:44 | bodyParameter | +| tst.js:12:32:12:44 | bodyParameter | +| tst.js:14:28:14:41 | queryParameter | +| tst.js:14:28:14:46 | queryParameter + "" | +| tst.js:14:28:14:46 | queryParameter + "" | +edges +| tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter | +| tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter | +| tst.js:5:9:5:46 | bodyParameter | tst.js:12:32:12:44 | bodyParameter | +| tst.js:5:9:5:46 | bodyParameter | tst.js:12:32:12:44 | bodyParameter | +| tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter | +| tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter | +| tst.js:5:25:5:46 | req.bod ... rameter | tst.js:5:9:5:46 | bodyParameter | +| tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter | +| tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter | +| tst.js:6:9:6:49 | queryParameter | tst.js:14:28:14:41 | queryParameter | +| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter | +| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter | +| tst.js:14:28:14:41 | queryParameter | tst.js:14:28:14:46 | queryParameter + "" | +| tst.js:14:28:14:41 | queryParameter | tst.js:14:28:14:46 | queryParameter + "" | +#select +| tst.js:8:28:8:40 | bodyParameter | tst.js:5:25:5:32 | req.body | tst.js:8:28:8:40 | bodyParameter | Template object injection due to $@. | tst.js:5:25:5:32 | req.body | user-provided value | +| tst.js:9:28:9:41 | queryParameter | tst.js:6:26:6:49 | req.que ... rameter | tst.js:9:28:9:41 | queryParameter | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value | +| tst.js:12:32:12:44 | bodyParameter | tst.js:5:25:5:32 | req.body | tst.js:12:32:12:44 | bodyParameter | Template object injection due to $@. | tst.js:5:25:5:32 | req.body | user-provided value | +| tst.js:14:28:14:46 | queryParameter + "" | tst.js:6:26:6:49 | req.que ... rameter | tst.js:14:28:14:46 | queryParameter + "" | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value | diff --git a/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.qlref b/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.qlref new file mode 100644 index 00000000000..4fcdae0f812 --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-073/TemplateObjectInjection.ql diff --git a/javascript/ql/test/experimental/Security/CWE-073/tst.js b/javascript/ql/test/experimental/Security/CWE-073/tst.js new file mode 100644 index 00000000000..b42ccea740a --- /dev/null +++ b/javascript/ql/test/experimental/Security/CWE-073/tst.js @@ -0,0 +1,17 @@ +var app = require('express')(); +app.set('view engine', 'hbs'); + +app.post('/path', function(req, res) { + var bodyParameter = req.body.bodyParameter; + var queryParameter = req.query.queryParameter; + + res.render('template', bodyParameter); // NOT OK + res.render('template', queryParameter); // NOT OK + + if (typeof bodyParameter === "string") { + res.render('template', bodyParameter); // OK - but still flagged [INCONSISTENCY] + } + res.render('template', queryParameter + ""); // OK - but still flagged [INCONSISTENCY] + + res.render('template', {profile: bodyParameter}); // OK +}); \ No newline at end of file From a5bde53bfe28df903ab846e2b51f8b4407b7d70d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 12:26:37 +0100 Subject: [PATCH 085/429] use the TaintedObject library in `js/template-object-injection` --- .../CWE-073/TemplateObjectInjection.ql | 27 +++++++++--- .../CWE-073/TemplateObjectInjection.expected | 42 +++++++++++++------ .../test/experimental/Security/CWE-073/tst.js | 17 ++++++-- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql index b1074ab618f..583255dfeb4 100644 --- a/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql @@ -11,8 +11,8 @@ */ import javascript -import DataFlow -import PathGraph +import DataFlow::PathGraph +import semmle.javascript.security.TaintedObject predicate isUsingHbsEngine() { Express::appCreation().getAMethodCall("set").getArgument(1).mayHaveStringValue("hbs") @@ -21,19 +21,34 @@ predicate isUsingHbsEngine() { class HbsLFRTaint extends TaintTracking::Configuration { HbsLFRTaint() { this = "HbsLFRTaint" } - override predicate isSource(Node node) { node instanceof RemoteFlowSource } + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } - override predicate isSink(Node node) { + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + TaintedObject::isSource(source, label) + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + label = TaintedObject::label() and exists(MethodCallExpr mc | Express::isResponse(mc.getReceiver()) and mc.getMethodName() = "render" and - node.asExpr() = mc.getArgument(1) and + sink.asExpr() = mc.getArgument(1) and isUsingHbsEngine() ) } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof TaintedObject::SanitizerGuard + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl + ) { + TaintedObject::step(src, trg, inlbl, outlbl) + } } -from HbsLFRTaint cfg, PathNode source, PathNode sink +from HbsLFRTaint cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Template object injection due to $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected b/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected index 455498d5d58..f8dc8d8f47d 100644 --- a/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected +++ b/javascript/ql/test/experimental/Security/CWE-073/TemplateObjectInjection.expected @@ -4,34 +4,52 @@ nodes | tst.js:5:25:5:32 | req.body | | tst.js:5:25:5:46 | req.bod ... rameter | | tst.js:6:9:6:49 | queryParameter | +| tst.js:6:9:6:49 | queryParameter | +| tst.js:6:26:6:49 | req.que ... rameter | | tst.js:6:26:6:49 | req.que ... rameter | | tst.js:6:26:6:49 | req.que ... rameter | | tst.js:8:28:8:40 | bodyParameter | | tst.js:8:28:8:40 | bodyParameter | | tst.js:9:28:9:41 | queryParameter | | tst.js:9:28:9:41 | queryParameter | -| tst.js:12:32:12:44 | bodyParameter | -| tst.js:12:32:12:44 | bodyParameter | -| tst.js:14:28:14:41 | queryParameter | -| tst.js:14:28:14:46 | queryParameter + "" | -| tst.js:14:28:14:46 | queryParameter + "" | +| tst.js:18:19:18:32 | queryParameter | +| tst.js:18:19:18:32 | queryParameter | +| tst.js:21:24:21:26 | obj | +| tst.js:21:24:21:26 | obj | +| tst.js:22:28:22:30 | obj | +| tst.js:22:28:22:30 | obj | +| tst.js:24:11:24:24 | str | +| tst.js:24:17:24:19 | obj | +| tst.js:24:17:24:24 | obj + "" | +| tst.js:27:28:27:42 | JSON.parse(str) | +| tst.js:27:28:27:42 | JSON.parse(str) | +| tst.js:27:39:27:41 | str | edges | tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter | | tst.js:5:9:5:46 | bodyParameter | tst.js:8:28:8:40 | bodyParameter | -| tst.js:5:9:5:46 | bodyParameter | tst.js:12:32:12:44 | bodyParameter | -| tst.js:5:9:5:46 | bodyParameter | tst.js:12:32:12:44 | bodyParameter | | tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter | | tst.js:5:25:5:32 | req.body | tst.js:5:25:5:46 | req.bod ... rameter | | tst.js:5:25:5:46 | req.bod ... rameter | tst.js:5:9:5:46 | bodyParameter | | tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter | | tst.js:6:9:6:49 | queryParameter | tst.js:9:28:9:41 | queryParameter | -| tst.js:6:9:6:49 | queryParameter | tst.js:14:28:14:41 | queryParameter | +| tst.js:6:9:6:49 | queryParameter | tst.js:18:19:18:32 | queryParameter | +| tst.js:6:9:6:49 | queryParameter | tst.js:18:19:18:32 | queryParameter | | tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter | | tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter | -| tst.js:14:28:14:41 | queryParameter | tst.js:14:28:14:46 | queryParameter + "" | -| tst.js:14:28:14:41 | queryParameter | tst.js:14:28:14:46 | queryParameter + "" | +| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter | +| tst.js:6:26:6:49 | req.que ... rameter | tst.js:6:9:6:49 | queryParameter | +| tst.js:18:19:18:32 | queryParameter | tst.js:21:24:21:26 | obj | +| tst.js:18:19:18:32 | queryParameter | tst.js:21:24:21:26 | obj | +| tst.js:21:24:21:26 | obj | tst.js:22:28:22:30 | obj | +| tst.js:21:24:21:26 | obj | tst.js:22:28:22:30 | obj | +| tst.js:21:24:21:26 | obj | tst.js:24:17:24:19 | obj | +| tst.js:24:11:24:24 | str | tst.js:27:39:27:41 | str | +| tst.js:24:17:24:19 | obj | tst.js:24:17:24:24 | obj + "" | +| tst.js:24:17:24:24 | obj + "" | tst.js:24:11:24:24 | str | +| tst.js:27:39:27:41 | str | tst.js:27:28:27:42 | JSON.parse(str) | +| tst.js:27:39:27:41 | str | tst.js:27:28:27:42 | JSON.parse(str) | #select | tst.js:8:28:8:40 | bodyParameter | tst.js:5:25:5:32 | req.body | tst.js:8:28:8:40 | bodyParameter | Template object injection due to $@. | tst.js:5:25:5:32 | req.body | user-provided value | | tst.js:9:28:9:41 | queryParameter | tst.js:6:26:6:49 | req.que ... rameter | tst.js:9:28:9:41 | queryParameter | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value | -| tst.js:12:32:12:44 | bodyParameter | tst.js:5:25:5:32 | req.body | tst.js:12:32:12:44 | bodyParameter | Template object injection due to $@. | tst.js:5:25:5:32 | req.body | user-provided value | -| tst.js:14:28:14:46 | queryParameter + "" | tst.js:6:26:6:49 | req.que ... rameter | tst.js:14:28:14:46 | queryParameter + "" | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value | +| tst.js:22:28:22:30 | obj | tst.js:6:26:6:49 | req.que ... rameter | tst.js:22:28:22:30 | obj | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value | +| tst.js:27:28:27:42 | JSON.parse(str) | tst.js:6:26:6:49 | req.que ... rameter | tst.js:27:28:27:42 | JSON.parse(str) | Template object injection due to $@. | tst.js:6:26:6:49 | req.que ... rameter | user-provided value | diff --git a/javascript/ql/test/experimental/Security/CWE-073/tst.js b/javascript/ql/test/experimental/Security/CWE-073/tst.js index b42ccea740a..9ff93d14cb5 100644 --- a/javascript/ql/test/experimental/Security/CWE-073/tst.js +++ b/javascript/ql/test/experimental/Security/CWE-073/tst.js @@ -9,9 +9,20 @@ app.post('/path', function(req, res) { res.render('template', queryParameter); // NOT OK if (typeof bodyParameter === "string") { - res.render('template', bodyParameter); // OK - but still flagged [INCONSISTENCY] + res.render('template', bodyParameter); // OK } - res.render('template', queryParameter + ""); // OK - but still flagged [INCONSISTENCY] + res.render('template', queryParameter + ""); // OK res.render('template', {profile: bodyParameter}); // OK -}); \ No newline at end of file + + indirect(res, queryParameter); +}); + +function indirect(res, obj) { + res.render("template", obj); // NOT OK + + const str = obj + ""; + res.render("template", str); // OK + + res.render("template", JSON.parse(str)); // NOT OK +} \ No newline at end of file From d016ba225286fd828c36833cbf6c35c861b6c5c6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 12:29:23 +0100 Subject: [PATCH 086/429] rename name dataflow configuration in `js/template-object-injection` --- .../Security/CWE-073/TemplateObjectInjection.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql index 583255dfeb4..8c5c19e6096 100644 --- a/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql @@ -18,8 +18,8 @@ predicate isUsingHbsEngine() { Express::appCreation().getAMethodCall("set").getArgument(1).mayHaveStringValue("hbs") } -class HbsLFRTaint extends TaintTracking::Configuration { - HbsLFRTaint() { this = "HbsLFRTaint" } +class TemplateObjInjectionConfig extends TaintTracking::Configuration { + TemplateObjInjectionConfig() { this = "TemplateObjInjectionConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } @@ -48,7 +48,7 @@ class HbsLFRTaint extends TaintTracking::Configuration { } } -from HbsLFRTaint cfg, DataFlow::PathNode source, DataFlow::PathNode sink +from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Template object injection due to $@.", source.getNode(), "user-provided value" From 2ace10fcdfb54ee3fe7f93a5cdddfd99aedfa534 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 3 Feb 2021 12:21:31 +0000 Subject: [PATCH 087/429] Use PostUpdateNode for wrapper method calls --- .../Security/CWE/CWE-522/InsecureLdapAuth.ql | 9 +++-- .../CWE-522/InsecureLdapAuth.expected | 36 +++++++++---------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql index b6e7b5ed702..8411a128c9c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.ql @@ -9,6 +9,7 @@ */ import java +import DataFlow import semmle.code.java.frameworks.Jndi import semmle.code.java.frameworks.Networking import semmle.code.java.dataflow.TaintTracking @@ -167,7 +168,9 @@ class BasicAuthFlowConfig extends DataFlow::Configuration { /** Source of `simple` configuration. */ override predicate isSource(DataFlow::Node src) { - exists(MethodAccess ma | isBasicAuthEnv(ma) and ma.getQualifier() = src.asExpr()) + exists(MethodAccess ma | + isBasicAuthEnv(ma) and ma.getQualifier() = src.(PostUpdateNode).getPreUpdateNode().asExpr() + ) } /** Sink of directory context creation. */ @@ -187,7 +190,9 @@ class SSLFlowConfig extends DataFlow::Configuration { /** Source of `ssl` configuration. */ override predicate isSource(DataFlow::Node src) { - exists(MethodAccess ma | isSSLEnv(ma) and ma.getQualifier() = src.asExpr()) + exists(MethodAccess ma | + isSSLEnv(ma) and ma.getQualifier() = src.(PostUpdateNode).getPreUpdateNode().asExpr() + ) } /** Sink of directory context creation. */ diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected index 1af36e67d05..863e8e55dcf 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.expected @@ -1,23 +1,21 @@ edges | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:20:49:20:59 | environment | -| InsecureLdapAuth.java:17:52:17:59 | "simple" : String | InsecureLdapAuth.java:20:49:20:59 | environment | +| InsecureLdapAuth.java:17:3:17:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:20:49:20:59 | environment | | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | InsecureLdapAuth.java:34:49:34:59 | environment | -| InsecureLdapAuth.java:31:52:31:59 | "simple" : String | InsecureLdapAuth.java:34:49:34:59 | environment | -| InsecureLdapAuth.java:45:52:45:59 | "simple" : String | InsecureLdapAuth.java:48:49:48:59 | environment | +| InsecureLdapAuth.java:31:3:31:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:34:49:34:59 | environment | +| InsecureLdapAuth.java:45:3:45:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:48:49:48:59 | environment | | InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | InsecureLdapAuth.java:63:49:63:59 | environment | -| InsecureLdapAuth.java:59:52:59:59 | "simple" : String | InsecureLdapAuth.java:63:49:63:59 | environment | -| InsecureLdapAuth.java:62:46:62:50 | "ssl" : String | InsecureLdapAuth.java:63:49:63:59 | environment | +| InsecureLdapAuth.java:59:3:59:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:63:49:63:59 | environment | +| InsecureLdapAuth.java:62:3:62:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:63:49:63:59 | environment | | InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:77:49:77:59 | environment | -| InsecureLdapAuth.java:88:52:88:59 | "simple" : String | InsecureLdapAuth.java:91:49:91:59 | environment | +| InsecureLdapAuth.java:88:3:88:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:91:49:91:59 | environment | | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:105:59:105:69 | environment | -| InsecureLdapAuth.java:102:52:102:59 | "simple" : String | InsecureLdapAuth.java:105:59:105:69 | environment | +| InsecureLdapAuth.java:102:3:102:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:105:59:105:69 | environment | | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | InsecureLdapAuth.java:120:49:120:59 | environment | -| InsecureLdapAuth.java:117:58:117:65 | "simple" : String | InsecureLdapAuth.java:120:49:120:59 | environment | +| InsecureLdapAuth.java:117:3:117:13 | environment [post update] : Hashtable | InsecureLdapAuth.java:120:49:120:59 | environment | | InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | -| InsecureLdapAuth.java:124:38:124:42 | "ssl" : String | InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | | InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | | InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | -| InsecureLdapAuth.java:128:44:128:51 | "simple" : String | InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | | InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | InsecureLdapAuth.java:142:50:142:60 | environment | | InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | InsecureLdapAuth.java:142:50:142:60 | environment | | InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | InsecureLdapAuth.java:142:50:142:60 | environment | @@ -25,37 +23,35 @@ edges | InsecureLdapAuth.java:152:16:152:26 | environment [post update] : Hashtable | InsecureLdapAuth.java:153:50:153:60 | environment | nodes | InsecureLdapAuth.java:11:20:11:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:17:52:17:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:17:3:17:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:20:49:20:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:20:49:20:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:25:20:25:39 | ... + ... : String | semmle.label | ... + ... : String | -| InsecureLdapAuth.java:31:52:31:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:31:3:31:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:34:49:34:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:34:49:34:59 | environment | semmle.label | environment | -| InsecureLdapAuth.java:45:52:45:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:45:3:45:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:48:49:48:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:53:20:53:50 | "ldap://ad.your-server.com:636" : String | semmle.label | "ldap://ad.your-server.com:636" : String | -| InsecureLdapAuth.java:59:52:59:59 | "simple" : String | semmle.label | "simple" : String | -| InsecureLdapAuth.java:62:46:62:50 | "ssl" : String | semmle.label | "ssl" : String | +| InsecureLdapAuth.java:59:3:59:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | +| InsecureLdapAuth.java:62:3:62:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:63:49:63:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:68:20:68:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | | InsecureLdapAuth.java:77:49:77:59 | environment | semmle.label | environment | -| InsecureLdapAuth.java:88:52:88:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:88:3:88:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:91:49:91:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:96:20:96:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:102:52:102:59 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:102:3:102:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:105:59:105:69 | environment | semmle.label | environment | | InsecureLdapAuth.java:105:59:105:69 | environment | semmle.label | environment | | InsecureLdapAuth.java:111:20:111:50 | "ldap://ad.your-server.com:389" : String | semmle.label | "ldap://ad.your-server.com:389" : String | -| InsecureLdapAuth.java:117:58:117:65 | "simple" : String | semmle.label | "simple" : String | +| InsecureLdapAuth.java:117:3:117:13 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:120:49:120:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:120:49:120:59 | environment | semmle.label | environment | | InsecureLdapAuth.java:124:3:124:5 | env [post update] : Hashtable | semmle.label | env [post update] : Hashtable | -| InsecureLdapAuth.java:124:38:124:42 | "ssl" : String | semmle.label | "ssl" : String | | InsecureLdapAuth.java:128:3:128:5 | env [post update] : Hashtable | semmle.label | env [post update] : Hashtable | -| InsecureLdapAuth.java:128:44:128:51 | "simple" : String | semmle.label | "simple" : String | | InsecureLdapAuth.java:135:20:135:39 | ... + ... : String | semmle.label | ... + ... : String | | InsecureLdapAuth.java:137:10:137:20 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | | InsecureLdapAuth.java:141:16:141:26 | environment [post update] : Hashtable | semmle.label | environment [post update] : Hashtable | From 8cf8b704c580191c34ec68a6fe3026160e866491 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 3 Feb 2021 16:16:48 +0100 Subject: [PATCH 088/429] C++: Add more indirection flow in dataflow models. Also revert the additions to DataFlowUtil added in #5035 as they can add too much flow. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 21 --------------- .../implementations/IdentityFunction.qll | 2 ++ .../cpp/models/implementations/Iterator.qll | 7 +++++ .../cpp/models/implementations/StdString.qll | 27 +++++++++++++++++++ .../cpp/models/implementations/Strset.qll | 3 +++ 5 files changed, 39 insertions(+), 21 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index aba8e3bceec..37bcd335172 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -911,27 +911,6 @@ private predicate modelFlow(Operand opFrom, Instruction iTo) { ) ) ) - or - impliedModelFlow(opFrom, iTo) -} - -/** - * When a `DataFlowFunction` specifies dataflow from a parameter `p` to the return value there should - * also be dataflow from the parameter dereference (i.e., `*p`) to the return value dereference. - */ -private predicate impliedModelFlow(Operand opFrom, Instruction iTo) { - exists( - CallInstruction call, DataFlowFunction func, FunctionInput modelIn, FunctionOutput modelOut, - int index - | - call.getStaticCallTarget() = func and - func.hasDataFlow(modelIn, modelOut) - | - modelIn.isParameterOrQualifierAddress(index) and - modelOut.isReturnValue() and - opFrom = getSideEffectFor(call, index).(ReadSideEffectInstruction).getSideEffectOperand() and - iTo = call // TODO: Add write side effects for return values - ) } /** diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll index 0178cd0f7ec..bd188cffe49 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll @@ -32,5 +32,7 @@ private class IdentityFunction extends DataFlowFunction, SideEffectFunction, Ali override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // These functions simply return the argument value. input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and output.isReturnValueDeref() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index 3a789a6aa25..a5b1c0e83ec 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -109,6 +109,8 @@ private class IteratorCrementOperator extends Operator, DataFlowFunction { override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input = iteratorInput and output.isReturnValue() + or + input.isParameterDeref(0) and output.isReturnValueDeref() } } @@ -159,6 +161,8 @@ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunctio override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -201,6 +205,9 @@ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunc or input.isReturnValueDeref() and output.isQualifierObject() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 8fd2f79cfdd..9f4c458815f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -293,6 +293,9 @@ private class StdIStreamIn extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -319,6 +322,9 @@ private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { // flow from first parameter to return value input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -361,6 +367,9 @@ private class StdIStreamRead extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -397,6 +406,9 @@ private class StdIStreamPutBack extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -430,6 +442,9 @@ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -453,6 +468,9 @@ private class StdGetLine extends DataFlowFunction, TaintFunction { // flow from first parameter to return value input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -486,6 +504,9 @@ private class StdOStreamOut extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -522,6 +543,9 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { // flow from first parameter to return value input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -605,6 +629,9 @@ private class StdStreamFunction extends DataFlowFunction, TaintFunction { // returns reference to `*this` input.isQualifierAddress() and output.isReturnValue() + or + input.isQualifierObject() and + output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll index f4a80cbabac..bf6430e548b 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll @@ -40,6 +40,9 @@ private class StrsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct // flow from the input string to the output string input.isParameter(0) and output.isReturnValue() + or + input.isParameterDeref(0) and + output.isReturnValueDeref() } override predicate parameterNeverEscapes(int index) { none() } From 3fafb47b1680fc7fb42418a1ca6816986262ab05 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 16:41:22 +0100 Subject: [PATCH 089/429] Python: Fix global flow A slightly odd fix, but still morally okay, I think. The main issue here was that global variables have their first occurrence in an inner scope inside a so-called "scope entry definition", that then subsequently flows to the first use of this variable. This meant that that first use was _not_ a `LocalSourceNode` (since _something_ flowed into it), and this blocked `trackUseNode` from type-tracking to it (as it expects all nodes to be `LocalSourceNode`s). The answer, then, is to say that a `LocalSourceNode` is simply one that doesn't have flow to it from _any `CfgNode`_ (through one or more steps). This disregards the flow from the scope entry definition, as that is flow from an `EssaNode`. Additionally, it makes sense to exclude `ModuleVariableNode`s. These should never be considered local sources, since they always have flow from (at least) the place where the corresponding global variable is introduced. --- .../semmle/python/dataflow/new/internal/DataFlowPublic.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index f2f90723d77..1cf756069f0 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -443,7 +443,10 @@ class BarrierGuard extends GuardNode { * - Function parameters */ class LocalSourceNode extends Node { - LocalSourceNode() { not simpleLocalFlowStep(_, this) } + LocalSourceNode() { + not simpleLocalFlowStep+(any(CfgNode n), this) and + not this instanceof ModuleVariableNode + } /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ cached From 93f91d8746182f425b5472f7c84f39dc72800591 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 3 Feb 2021 17:44:04 +0100 Subject: [PATCH 090/429] Python: Apply suggestions from code review Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- python/ql/src/semmle/python/frameworks/Tornado.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Tornado.qll b/python/ql/src/semmle/python/frameworks/Tornado.qll index 1f5859c4945..4351188d8bb 100644 --- a/python/ql/src/semmle/python/frameworks/Tornado.qll +++ b/python/ql/src/semmle/python/frameworks/Tornado.qll @@ -567,7 +567,7 @@ private module Tornado { // Response modeling // --------------------------------------------------------------------------- /** - * A call to `tornado.web.RequestHandler.redirect` method. + * A call to the `tornado.web.RequestHandler.redirect` method. * * See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.redirect */ @@ -591,7 +591,7 @@ private module Tornado { } /** - * A call to `tornado.web.RequestHandler.write` method. + * A call to the `tornado.web.RequestHandler.write` method. * * See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.write */ From 724c3e00e02be120f2a48630c2bc6ab6dfa9fd32 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 3 Feb 2021 16:45:15 +0000 Subject: [PATCH 091/429] Update help file --- .../experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp index ee4afabbed6..c729759a06e 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-522/InsecureLdapAuth.qhelp @@ -15,11 +15,6 @@ -
  • - CWE: - CWE-522: Insufficiently Protected Credentials - CWE-319: Cleartext Transmission of Sensitive Information -
  • Oracle: LDAP and LDAPS URLs From 6ce160c51c9276704d0b414119737f4a5bce830e Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 19:49:53 +0100 Subject: [PATCH 092/429] Python: Use call instead of invocation --- python/ql/src/semmle/python/ApiGraphs.qll | 2 +- .../python/dataflow/new/internal/DataFlowPublic.qll | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 2c1ff3b6cf7..e8072a91540 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -292,7 +292,7 @@ module API { or // Calling a node that is a use of `base` lbl = Label::return() and - ref = pred.getAnInvocation() + ref = pred.getACall() ) } diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 1cf756069f0..b2e2298182e 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -477,9 +477,9 @@ class LocalSourceNode extends Node { AttrRead getAnAttributeRead() { result = getAnAttributeReference() } /** - * Gets an invocation (with our without `new`) of this node. + * Gets a call to this node. */ - Node getAnInvocation() { Cached::invocation(this, result) } + Node getACall() { Cached::call(this, result) } } cached @@ -521,12 +521,12 @@ private module Cached { } /** - * Holds if `func` flows to the callee of `invoke`. + * Holds if `func` flows to the callee of `call`. */ cached - predicate invocation(LocalSourceNode func, Node invoke) { - exists(CfgNode n, CallNode call | - invoke.asCfgNode() = call and n.asCfgNode() = call.getFunction() + predicate call(LocalSourceNode func, Node call) { + exists(CfgNode n, CallNode call_node | + call.asCfgNode() = call_node and n.asCfgNode() = call_node.getFunction() | hasLocalSource(n, func) ) From c5d6792c1eb727cd5fd1f8a6e84fd296c2e0e5bd Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 19:50:21 +0100 Subject: [PATCH 093/429] Python: Make `toString` abstract --- python/ql/src/semmle/python/ApiGraphs.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index e8072a91540..d4091a7a2bf 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -146,9 +146,7 @@ module API { /** * Gets a textual representation of this node. */ - string toString() { - none() // defined in subclasses - } + abstract string toString(); /** * Gets a path of the given `length` from the root to this node. From 05f290f7347c8c213461c66a999dad26c941a5b6 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 19:51:34 +0100 Subject: [PATCH 094/429] Python: Better explanation in `use/3` --- python/ql/src/semmle/python/ApiGraphs.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index d4091a7a2bf..04eeb785c5b 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -282,6 +282,13 @@ module API { cached predicate use(TApiNode base, string lbl, DataFlow::Node ref) { exists(DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode pred | + // First, we find a predecessor of the node `ref` that we want to determine. The predecessor + // is any node that is a type-tracked use of a data flow node (`src`), which is itself a + // reference to the API node `base`. + // + // Once we have identified the predecessor, we define its relation to the successor `ref` as + // well as the label on the edge from `pred` to `ref`. This label describes the nature of + // the relationship between `pred` and `ref`. use(base, src) and pred = trackUseNode(src) | // Reading an attribute on a node that is a use of `base`: From 56515c570879f89baeed251c091cc8b528ade9fd Mon Sep 17 00:00:00 2001 From: Taus Date: Wed, 3 Feb 2021 21:29:15 +0100 Subject: [PATCH 095/429] Python: Improve documentation for `moduleImport` Co-authored-by: Rasmus Wriedt Larsen --- python/ql/src/semmle/python/ApiGraphs.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 04eeb785c5b..54ae9f86875 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -196,7 +196,13 @@ module API { /** Gets the root node. */ Root root() { any() } - /** Gets a node corresponding to an import of module `m`. */ + /** + * Gets a node corresponding to an import of module `m`. + * + * Note: You should only use this predicate for top level modules. If you want nodes corresponding to a submodule, + * you should use `.getMember` on the parent module. For example, for nodes corresponding to the module `foo.bar`, + * use `moduleImport("foo").getMember("bar")`. + */ Node moduleImport(string m) { result = Impl::MkModuleImport(m) } /** From cccca879d959caf17d0ed26350e82385a0ba5294 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 3 Feb 2021 21:52:00 +0100 Subject: [PATCH 096/429] C#: Add initial DB scheme --- .../initial/semmlecode.csharp.dbscheme | 1707 +++++++++++++++++ 1 file changed, 1707 insertions(+) create mode 100644 csharp/upgrades/initial/semmlecode.csharp.dbscheme diff --git a/csharp/upgrades/initial/semmlecode.csharp.dbscheme b/csharp/upgrades/initial/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..34565707dfb --- /dev/null +++ b/csharp/upgrades/initial/semmlecode.csharp.dbscheme @@ -0,0 +1,1707 @@ +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + varchar(900) queryPath: string ref, + int location: @location ref, + varchar(900) message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + varchar(900) queryPath: string ref, + int location: @location ref, + float value: float ref); + +externalData( + int id: @externalDataElement, + varchar(900) path: string ref, + int column: int ref, + varchar(900) value: string ref); + +snapshotDate( + unique date snapshotDate: date ref); + +sourceLocationPrefix( + varchar(900) prefix: string ref); + +/* + * Duplicate code + */ + +duplicateCode( + unique int id: @duplication, + varchar(900) relativePath: string ref, + int equivClass: int ref); + +similarCode( + unique int id: @similarity, + varchar(900) 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); + +/* + * Version history + */ + +svnentries( + int id: @svnentry, + varchar(500) revision: string ref, + varchar(500) author: string ref, + date revisionDate: date ref, + int changeSize: int ref); + +svnaffectedfiles( + int id: @svnentry ref, + int file: @file ref, + varchar(500) action: string ref); + +svnentrymsg( + int id: @svnentry ref, + varchar(500) message: string ref +) + +svnchurn( + int commit: @svnentry ref, + int file: @file ref, + int addedLines: int ref, + int deletedLines: int ref); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +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); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + unique int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + varchar(900) fullname: string ref, + varchar(900) name: string ref, + varchar(900) version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + varchar(900) name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + varchar(900) name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + varchar(900) name: string ref); + +typeref_type( + unique int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @struct_type ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +is_generic(unique int id: @generic ref); + +is_constructed(unique int id: @generic ref); + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor; + +modifiers( + unique int id: @modifier, + varchar(900) name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @literal_expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + varchar(900) name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + varchar(900) name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + varchar(900) name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + varchar(900) name: string ref, + varchar(900) symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + unique int id: @variable ref, + varchar(900) value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + unique int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + unique int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + varchar(900) name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +@ref_callable = @local_function | @method | @delegate_type; + +ref_returns(int fn: @ref_callable ref); + +ref_readonly_returns(int fn: @ref_callable ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + varchar(900) name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + varchar(900) name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + varchar(900) name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case +| 30 = @local_function_stmt + ; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + varchar(900) value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + varchar(900) name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + varchar(900) name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* XML Files */ + +xmlEncoding ( + unique int id: @file ref, + varchar(900) encoding: string ref); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) 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, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + varchar(800) text: string ref, + varchar(800) rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + varchar(1000) name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + varchar(1000) name: string ref); +asp_element_body( + unique int element: @asp_element ref, + varchar(1000) body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + varchar(1000) name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + varchar(1000) name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + varchar(900) value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +; + +cil_type( + unique int id: @cil_type, + varchar(900) name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_method( + unique int id: @cil_method, + varchar(900) name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + varchar(900) name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; + +#keyset[method, index] +cil_parameter( + unique int id: @cil_parameter, + int method: @cil_method ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + varchar(900) name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + varchar(900) name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + varchar(100) param: string ref, + varchar(900) value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + varchar(900) value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) From b5633625b37460046eecf649fa6672233fa37ed8 Mon Sep 17 00:00:00 2001 From: yoff Date: Wed, 3 Feb 2021 21:56:03 +0100 Subject: [PATCH 097/429] Update python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll Co-authored-by: Rasmus Wriedt Larsen --- .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index 2ab91694217..e17305ee355 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1323,7 +1323,8 @@ module IterableUnpacking { predicate iterableUnpackingForReadStep(CfgNode nodeFrom, Content c, Node nodeTo) { exists(ForTarget target | nodeFrom.asExpr() = target.getSource() and - nodeTo = TIterableSequenceNode(target.(SequenceNode)) + target instanceof SequenceNode and + nodeTo = TIterableSequenceNode(target) ) and ( c instanceof ListElementContent From a7ca065411166b2c0a388ee225ef95bfe748be88 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 3 Feb 2021 22:14:15 +0100 Subject: [PATCH 098/429] Python: Fix `ForTarget` --- .../dataflow/new/internal/DataFlowPrivate.qll | 2 +- .../dataflow/coverage/dataflow.expected | 44 +++++++++++++++++++ .../experimental/dataflow/coverage/test.py | 4 +- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index e17305ee355..10ced3c768c 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -1253,7 +1253,7 @@ module IterableUnpacking { or exists(Comp comp | source = comp.getIterable() and - this.getNode() = comp.getIterationVariable(0).getAStore() + this.getNode() = comp.getNthInnerLoop(0).getTarget() ) } diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.expected b/python/ql/test/experimental/dataflow/coverage/dataflow.expected index 978b810ea23..ff3d518d1bc 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.expected +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.expected @@ -95,6 +95,26 @@ edges | test.py:199:33:199:40 | ControlFlowNode for List [List element] | test.py:199:28:199:28 | SSA variable z | | test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:199:33:199:40 | ControlFlowNode for List [List element] | | test.py:200:10:200:10 | ControlFlowNode for x [List element] | test.py:200:10:200:13 | ControlFlowNode for Subscript | +| test.py:205:9:205:47 | ControlFlowNode for ListComp [List element] | test.py:206:10:206:10 | ControlFlowNode for x [List element] | +| test.py:205:10:205:10 | ControlFlowNode for a | test.py:205:9:205:47 | ControlFlowNode for ListComp [List element] | +| test.py:205:17:205:17 | SSA variable a | test.py:205:10:205:10 | ControlFlowNode for a | +| test.py:205:17:205:20 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:205:17:205:17 | SSA variable a | +| test.py:205:17:205:20 | IterableSequence [Tuple element at index 0] | test.py:205:17:205:20 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:205:26:205:46 | ControlFlowNode for List [List element, Tuple element at index 0] | test.py:205:17:205:20 | IterableSequence [Tuple element at index 0] | +| test.py:205:28:205:33 | ControlFlowNode for SOURCE | test.py:205:28:205:44 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:205:28:205:44 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:205:26:205:46 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:206:10:206:10 | ControlFlowNode for x [List element] | test.py:206:10:206:13 | ControlFlowNode for Subscript | +| test.py:210:9:210:51 | ControlFlowNode for ListComp [List element] | test.py:211:10:211:10 | ControlFlowNode for x [List element] | +| test.py:210:10:210:10 | ControlFlowNode for a [List element] | test.py:210:10:210:13 | ControlFlowNode for Subscript | +| test.py:210:10:210:13 | ControlFlowNode for Subscript | test.py:210:9:210:51 | ControlFlowNode for ListComp [List element] | +| test.py:210:20:210:21 | IterableElement | test.py:210:20:210:21 | SSA variable a [List element] | +| test.py:210:20:210:21 | SSA variable a [List element] | test.py:210:10:210:10 | ControlFlowNode for a [List element] | +| test.py:210:20:210:24 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:210:20:210:21 | IterableElement | +| test.py:210:20:210:24 | IterableSequence [Tuple element at index 0] | test.py:210:20:210:24 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:210:30:210:50 | ControlFlowNode for List [List element, Tuple element at index 0] | test.py:210:20:210:24 | IterableSequence [Tuple element at index 0] | +| test.py:210:32:210:37 | ControlFlowNode for SOURCE | test.py:210:32:210:48 | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:210:32:210:48 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:210:30:210:50 | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:211:10:211:10 | ControlFlowNode for x [List element] | test.py:211:10:211:13 | ControlFlowNode for Subscript | | test.py:349:11:349:16 | ControlFlowNode for SOURCE | test.py:349:11:349:17 | ControlFlowNode for Tuple [Tuple element at index 0] | | test.py:349:11:349:17 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:349:10:349:21 | ControlFlowNode for Subscript | | test.py:353:10:353:17 | ControlFlowNode for List [List element] | test.py:353:10:353:20 | ControlFlowNode for Subscript | @@ -440,6 +460,28 @@ nodes | test.py:199:34:199:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:200:10:200:10 | ControlFlowNode for x [List element] | semmle.label | ControlFlowNode for x [List element] | | test.py:200:10:200:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:205:9:205:47 | ControlFlowNode for ListComp [List element] | semmle.label | ControlFlowNode for ListComp [List element] | +| test.py:205:10:205:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a | +| test.py:205:17:205:17 | SSA variable a | semmle.label | SSA variable a | +| test.py:205:17:205:20 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:205:17:205:20 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] | +| test.py:205:26:205:46 | ControlFlowNode for List [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:205:28:205:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:205:28:205:44 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:206:10:206:10 | ControlFlowNode for x [List element] | semmle.label | ControlFlowNode for x [List element] | +| test.py:206:10:206:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:210:9:210:51 | ControlFlowNode for ListComp [List element] | semmle.label | ControlFlowNode for ListComp [List element] | +| test.py:210:10:210:10 | ControlFlowNode for a [List element] | semmle.label | ControlFlowNode for a [List element] | +| test.py:210:10:210:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | +| test.py:210:20:210:21 | IterableElement | semmle.label | IterableElement | +| test.py:210:20:210:21 | SSA variable a [List element] | semmle.label | SSA variable a [List element] | +| test.py:210:20:210:24 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:210:20:210:24 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] | +| test.py:210:30:210:50 | ControlFlowNode for List [List element, Tuple element at index 0] | semmle.label | ControlFlowNode for List [List element, Tuple element at index 0] | +| test.py:210:32:210:37 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | +| test.py:210:32:210:48 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | +| test.py:211:10:211:10 | ControlFlowNode for x [List element] | semmle.label | ControlFlowNode for x [List element] | +| test.py:211:10:211:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | test.py:349:10:349:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript | | test.py:349:11:349:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE | | test.py:349:11:349:17 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] | @@ -722,6 +764,8 @@ nodes | test.py:184:10:184:13 | ControlFlowNode for Subscript | test.py:183:23:183:28 | ControlFlowNode for SOURCE | test.py:184:10:184:13 | ControlFlowNode for Subscript | Flow found | | test.py:189:10:189:13 | ControlFlowNode for Subscript | test.py:188:25:188:30 | ControlFlowNode for SOURCE | test.py:189:10:189:13 | ControlFlowNode for Subscript | Flow found | | test.py:200:10:200:13 | ControlFlowNode for Subscript | test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:200:10:200:13 | ControlFlowNode for Subscript | Flow found | +| test.py:206:10:206:13 | ControlFlowNode for Subscript | test.py:205:28:205:33 | ControlFlowNode for SOURCE | test.py:206:10:206:13 | ControlFlowNode for Subscript | Flow found | +| test.py:211:10:211:13 | ControlFlowNode for Subscript | test.py:210:32:210:37 | ControlFlowNode for SOURCE | test.py:211:10:211:13 | ControlFlowNode for Subscript | Flow found | | test.py:349:10:349:21 | ControlFlowNode for Subscript | test.py:349:11:349:16 | ControlFlowNode for SOURCE | test.py:349:10:349:21 | ControlFlowNode for Subscript | Flow found | | test.py:353:10:353:20 | ControlFlowNode for Subscript | test.py:353:11:353:16 | ControlFlowNode for SOURCE | test.py:353:10:353:20 | ControlFlowNode for Subscript | Flow found | | test.py:357:10:357:27 | ControlFlowNode for Subscript | test.py:357:16:357:21 | ControlFlowNode for SOURCE | test.py:357:10:357:27 | ControlFlowNode for Subscript | Flow found | diff --git a/python/ql/test/experimental/dataflow/coverage/test.py b/python/ql/test/experimental/dataflow/coverage/test.py index 0da8b40b274..2fdf9a9984d 100644 --- a/python/ql/test/experimental/dataflow/coverage/test.py +++ b/python/ql/test/experimental/dataflow/coverage/test.py @@ -203,12 +203,12 @@ def test_nested_comprehension_paren(): # Iterable unpacking in comprehensions def test_unpacking_comprehension(): x = [a for (a, b) in [(SOURCE, NONSOURCE)]] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" def test_star_unpacking_comprehension(): x = [a[0] for (*a, b) in [(SOURCE, NONSOURCE)]] - SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]" + SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]" # 6.2.8. Generator expressions From ebfb1faf779f45a063da91a8db21bd711bf83aaf Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 22:26:46 +0100 Subject: [PATCH 099/429] Python: Autoformat --- python/ql/src/semmle/python/ApiGraphs.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 54ae9f86875..6928d83477a 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -196,11 +196,11 @@ module API { /** Gets the root node. */ Root root() { any() } - /** - * Gets a node corresponding to an import of module `m`. + /** + * Gets a node corresponding to an import of module `m`. * * Note: You should only use this predicate for top level modules. If you want nodes corresponding to a submodule, - * you should use `.getMember` on the parent module. For example, for nodes corresponding to the module `foo.bar`, + * you should use `.getMember` on the parent module. For example, for nodes corresponding to the module `foo.bar`, * use `moduleImport("foo").getMember("bar")`. */ Node moduleImport(string m) { result = Impl::MkModuleImport(m) } From ba98b08001886288414f96511d5d284dc9c4c0b6 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 22:31:33 +0100 Subject: [PATCH 100/429] Python: Further elaboration of `use/3` --- python/ql/src/semmle/python/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 6928d83477a..49f1ee1303c 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -290,7 +290,7 @@ module API { exists(DataFlow::LocalSourceNode src, DataFlow::LocalSourceNode pred | // First, we find a predecessor of the node `ref` that we want to determine. The predecessor // is any node that is a type-tracked use of a data flow node (`src`), which is itself a - // reference to the API node `base`. + // reference to the API node `base`. Thus, `pred` and `src` both represent uses of `base`. // // Once we have identified the predecessor, we define its relation to the successor `ref` as // well as the label on the edge from `pred` to `ref`. This label describes the nature of From 5974af661e1c8d11aa92c5fb36ee41e10f616202 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 3 Feb 2021 22:43:21 +0100 Subject: [PATCH 101/429] Python: Update test file Makes the `a.b.c.d` test more sensible. Also adds a test that shows a case where we're currently _not_ getting the right flow. --- .../experimental/dataflow/ApiGraphs/test.py | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py index c361e3a169f..8137066ad6f 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -22,13 +22,46 @@ abc = ab.c #$ use=moduleImport("a").getMember("b").getMember("c") abcd = abc.d #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d") -x5 = abcd() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getReturn() +x5 = abcd.method() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getMember("method").getReturn() -y5 = x5.method() #$ use=moduleImport("a").getMember("b").getMember("c").getMember("d").getReturn().getMember("method").getReturn() +from a6 import m6 #$ use=moduleImport("a6").getMember("m6") + +x6 = m6().foo().bar() #$ use=moduleImport("a6").getMember("m6").getReturn().getMember("foo").getReturn().getMember("bar").getReturn() # Relative imports. These are ignored from .foo import bar -from ..foobar import baz \ No newline at end of file +from ..foobar import baz + + +# Use of imports across scopes + +def use_m4(): + x = m4.blah4 #$ use=moduleImport("a4").getMember("b4").getMember("c4").getMember("blah4") + +def local_import_use(): + from foo import bar #$ use=moduleImport("foo").getMember("bar") + + x = bar() #$ use=moduleImport("foo").getMember("bar").getReturn() + +from eggs import ham as spam #$ use=moduleImport("eggs").getMember("ham") + +def bbb(): + f = spam #$ use=moduleImport("eggs").getMember("ham") + +from danger import SOURCE #$ use=moduleImport("danger").getMember("SOURCE") + +foo = SOURCE #$ use=moduleImport("danger").getMember("SOURCE") + +def change_foo(): + global foo + foo = SOURCE #$ use=moduleImport("danger").getMember("SOURCE") + +def f(): + global foo + sink(foo) #$ use=moduleImport("danger").getMember("SOURCE") + foo = NONSOURCE + change_foo() + sink(foo) #$ MISSING: use=moduleImport("danger").getMember("SOURCE") From 5e1e27c2b6b3429623b66531d4fe0b090e70638a Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Wed, 3 Feb 2021 15:12:31 -0800 Subject: [PATCH 102/429] Adding queries related to the Solorigate campaign --- .../backdoor/DangerousNativeFunctionCall.ql | 53 ++++++ .../DangerousNativeFunctionCall.qlhelp | 8 + .../backdoor/PotentialTimeBomb.ql | 153 ++++++++++++++++ .../backdoor/ProcessNameToHashTaintFlow.ql | 57 ++++++ .../ProcessNameToHashTaintFlow.qlhelp | 9 + .../campaign/Solorigate-Readme.md | 121 +++++++++++++ .../ModifedFnvFunctionDetection.qhelp | 12 ++ .../Solorigate/ModifedFnvFunctionDetection.ql | 32 ++++ .../NumberOfKnownCommandsAboveThreshold.qhelp | 12 ++ .../NumberOfKnownCommandsAboveThreshold.ql | 20 +++ .../NumberOfKnownHashesAboveThreshold.qhelp | 13 ++ .../NumberOfKnownHashesAboveThreshold.ql | 23 +++ .../NumberOfKnownLiteralsAboveThreshold.qhelp | 13 ++ .../NumberOfKnownLiteralsAboveThreshold.ql | 23 +++ ...mberOfKnownMethodNamesAboveThreshold.qhelp | 13 ++ .../NumberOfKnownMethodNamesAboveThreshold.ql | 23 +++ .../campaign/Solorigate/Solorigate.qhelp | 13 ++ .../campaign/Solorigate/Solorigate.qll | 163 ++++++++++++++++++ .../SwallowEverythingExceptionHandler.qhelp | 12 ++ .../SwallowEverythingExceptionHandler.ql | 30 ++++ .../Cryptography/NonCryptographicHashes.qll | 108 ++++++++++++ 21 files changed, 911 insertions(+) create mode 100644 csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql create mode 100644 csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlhelp create mode 100644 csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql create mode 100644 csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql create mode 100644 csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp create mode 100644 csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql create mode 100644 csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql new file mode 100644 index 00000000000..cbc42c41ddb --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql @@ -0,0 +1,53 @@ +/** + * @name Potential dangerous use of native functions + * @description Please review code for possible malicious intent or unsafe handling. + * @kind problem + * @problem.severity warning + * @precision low + * @id cs/backdoor/dangerous-native-functions + * @tags security + * solorigate + */ + +import csharp +import semmle.code.csharp.frameworks.system.runtime.InteropServices + +predicate isDangerousMethod(Method m) { + m.getName() = "OpenProcessToken" or + m.getName() = "OpenThreadToken" or + m.getName() = "DuplicateToken" or + m.getName() = "DuplicateTokenEx" or + m.getName().matches("LogonUser%") or + m.getName().matches("WNetAddConnection%") or + m.getName() = "DeviceIoControl" or + m.getName().matches ("LoadLibrary%") or + m.getName() = "GetProcAddress" or + m.getName().matches ("CreateProcess%") or + m.getName().matches ("InitiateSystemShutdown%") or + m.getName() = "GetCurrentProcess" or + m.getName() = "GetCurrentProcessToken" or + m.getName() = "GetCurrentThreadToken" or + m.getName() = "GetCurrentThreadEffectiveToken" or + m.getName() = "OpenThreadToken" or + m.getName() = "SetTokenInformation" or + m.getName().matches ("LookupPrivilegeValue%") or + m.getName() = "AdjustTokenPrivileges" or + m.getName() = "SetProcessPrivilege" or + m.getName() = "ImpersonateLoggedOnUser" or + m.getName().matches ("Add%Ace%") +} + +predicate isExternMethod(Method externMethod) { + externMethod.isExtern() + or + externMethod.getAnAttribute().getType() instanceof + SystemRuntimeInteropServicesDllImportAttributeClass + or + externMethod.getDeclaringType().getAnAttribute().getType() instanceof + SystemRuntimeInteropServicesComImportAttributeClass +} + +from MethodCall mc +where isExternMethod(mc.getTarget()) +and isDangerousMethod(mc.getTarget()) +select mc, "Call to an external method $@", mc, mc.toString() \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlhelp b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlhelp new file mode 100644 index 00000000000..8d1aff62988 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlhelp @@ -0,0 +1,8 @@ + + + +

    This query finds native calls to external functions that are often used in creating backdoors or are generally attributed to unsafe code practices.

    +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql new file mode 100644 index 00000000000..367ec6955e2 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -0,0 +1,153 @@ +/** + * @name Potential Timebomb + * @description Flow from a file last modification date (very likely implant installation time) and an offset to condition statement (the trigger) + * @kind problem + * @precision Low + * @problem.severity warning + * @id cs/backdoor/potential-time-bomb + * @tags security + * solorigate + */ + +import csharp +import DataFlow + +/** + * Class that will help to find the source for the trigger file-modification date. + * + * May be extended as new patterns for similar time bombs are found. + */ +class GetLastWriteTimeMethod extends Method { + GetLastWriteTimeMethod() { + this.getQualifiedName() in [ "System.IO.File.GetLastWriteTime", "System.IO.File.GetFileCreationTime", "System.IO.File.GetCreationTimeUtc", "System.IO.File.GetLastAccessTimeUtc" ] + } +} + +/** + * Abstracts `System.DateTime` structure + */ +class DateTimeStruct extends Struct { + DateTimeStruct() { + this.getQualifiedName() = "System.DateTime" + } + + /** + * holds if the Callable is used for DateTime arithmetic operations + */ + Callable getATimeSpanArtithmeticCallable() { + ( result = this.getAnOperator() or result = this.getAMethod()) and + ( result.getName() in ["Add", "AddDays", "AddHours", "AddMilliseconds", "AddMinutes", "AddMonths", "AddSeconds", "AddTicks", "AddYears", "+", "-"] ) + } + + /** + * Holds if the Callable is used for DateTime comparision + */ + Callable getAComparisonCallable() { + ( result = this.getAnOperator() or result = this.getAMethod()) and + ( result.getName() in ["Compare", "CompareTo", "Equals", "==", "!=", "<", ">", "<=", ">="] ) + } +} + +/** + * Dataflow configuration to find flow from a GetLastWriteTime source to a DateTime arithmetic operation + */ +private class FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable extends TaintTracking::Configuration { + FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable() { + this = "FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable" + } + + override + predicate isSource(DataFlow::Node source) { + exists( Call call, GetLastWriteTimeMethod m | + m.getACall() = call and + source.asExpr() = call + ) + } + + override + predicate isSink(DataFlow::Node sink) { + exists( Call call, DateTimeStruct dateTime | + call.getAChild*() = sink.asExpr() and + call = dateTime.getATimeSpanArtithmeticCallable().getACall() + ) + } +} + +/** + * Dataflow configuration to find flow from a DateTime arithmetic operation to a DateTime comparison operation + */ +private class FlowsFromTimeSpanArithmeticToTimeComparisonCallable extends TaintTracking::Configuration { + FlowsFromTimeSpanArithmeticToTimeComparisonCallable() { + this = "FlowsFromTimeSpanArithmeticToTimeComparisonCallable" + } + + override + predicate isSource(DataFlow::Node source) { + exists( DateTimeStruct dateTime, Call call | + source.asExpr() = call | + call = dateTime.getATimeSpanArtithmeticCallable().getACall() + ) + } + + override + predicate isSink(DataFlow::Node sink) { + exists( Call call, DateTimeStruct dateTime | + call.getAnArgument().getAChild*() = sink.asExpr() and + call = dateTime.getAComparisonCallable().getACall() + ) + + } +} + +/** + * Dataflow configuration to find flow from a DateTime comparison operation to a Selection Statement (such as an If) + */ +private class FlowsFromTimeComparisonCallableToSelectionStatementCondition extends TaintTracking::Configuration { + FlowsFromTimeComparisonCallableToSelectionStatementCondition() { + this = "FlowsFromTimeComparisonCallableToSelectionStatementCondition" + } + + override + predicate isSource(DataFlow::Node source) { + exists( DateTimeStruct dateTime, Call call | + source.asExpr() = call | + call = dateTime.getAComparisonCallable().getACall() + ) + } + + override + predicate isSink(DataFlow::Node sink) { + exists( SelectionStmt sel | + sel.getCondition().getAChild*() = sink.asExpr() + ) + + } +} + +/** + * Holds if the last file modification date from the call to getLastWriteTimeMethodCall will be used in a DateTime arithmetic operation timeArithmeticCall, + * which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger + */ +predicate isPotentialTimeBomb( Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement ) { + exists( FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable config1, Node sink, DateTimeStruct dateTime, + FlowsFromTimeSpanArithmeticToTimeComparisonCallable config2, Node sink2, + FlowsFromTimeComparisonCallableToSelectionStatementCondition config3, Node sink3 | + config1.hasFlow(exprNode(getLastWriteTimeMethodCall), sink) and + timeArithmeticCall = dateTime.getATimeSpanArtithmeticCallable().getACall() and + timeArithmeticCall.getAChild*() = sink.asExpr() and + config2.hasFlow(exprNode(timeArithmeticCall), sink2) and + timeComparisonCall = dateTime.getAComparisonCallable().getACall() and + timeComparisonCall.getAnArgument().getAChild*() = sink2.asExpr() and + config3.hasFlow(exprNode(timeComparisonCall), sink3) and + selStatement.getCondition().getAChild*() = sink3.asExpr() + ) +} + +from Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement +where isPotentialTimeBomb( getLastWriteTimeMethodCall, timeArithmeticCall, timeComparisonCall, selStatement ) +select selStatement, "Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger." + , timeComparisonCall, timeComparisonCall.toString() + , timeArithmeticCall, "an offset" + ,getLastWriteTimeMethodCall, "last modification time of a file" + + diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql new file mode 100644 index 00000000000..63085f75ddc --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -0,0 +1,57 @@ +/** + * @name ProcessName to hash function flow + * @description Flow from a function retrieving process name to a hash function + * @kind problem + * @tags security + * solorigate + * @problem.severity warning + * @precision medium + * @id cs/backdoor/process-name-to-hash-function + */ + +import csharp +import DataFlow +import microsoft.code.csharp.Cryptography.NonCryptographicHashes + +class DataFlowFromMethodToHash extends TaintTracking::Configuration { + DataFlowFromMethodToHash() { + this = "DataFlowFromMethodNameToHashFunction" + } + /** + * Holds if `source` is a relevant data flow source. + */ + override predicate isSource(Node source) + { + isSuspiciousPropertyName(source.asExpr()) + } + + /** + * Holds if `sink` is a relevant data flow sink. + */ + override predicate isSink(Node sink) + { + isGetHash(sink.asExpr()) + } +} + +predicate isGetHash(Expr arg) { + exists (MethodCall mc | + (mc.getTarget().getName().matches ("%Hash%") or + mc.getTarget().getName().regexpMatch("Md[4-5]|Sha[1-9]{1,3}") + ) + and + mc.getAnArgument() = arg) or + exists( Callable callable, Parameter param, Call call, int i | + isCallableAPotentialNonCryptographicHashFunction( callable, param ) and + callable.getParameter(i) = param and + call = callable.getACall() and + call.getArgument(i) = arg) +} + +predicate isSuspiciousPropertyName(PropertyRead pr) { + pr.getTarget().getQualifiedName() = "System.Diagnostics.Process.ProcessName" +} + +from Node src, Node sink, DataFlowFromMethodToHash conf +where conf.hasFlow(src, sink) +select src, "The hash is calculated on the process name $@, may be related to a backdoor. Please review the code for possible malicious intent.", sink, "here" \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlhelp b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlhelp new file mode 100644 index 00000000000..39d21b32b72 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlhelp @@ -0,0 +1,9 @@ + + + +

    This query detects code flow from PorcessName property on the Process class into a hash function.

    +

    Such flow is often used in code backdoors to detect runnig processes and compare them to an obfuscated list of antivirus processes to aviod detection.

    +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md b/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md new file mode 100644 index 00000000000..471fd9ed6f8 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md @@ -0,0 +1,121 @@ +# Working with Solorigate queries + +These queries hunt for Indicators of Compromise (IoCs) associated with the malicious implant code that was inserted into the SolarWinds Orion product. + +This ReadMe walks through what each query does and limitations of the approaches taken, suggestions for modifications, and general advice on using CodeQL to author backdoor hunting queries. There are two approaches taken with the queries; the first is to look for syntactic characteristics used in the malicious implant, things like names and particular literals. The second approach looks for semantic patterns – particular functionality and flow associated with the implant. + +When editing this queries for open sourcing, we tried to find the right balance between detection capability and false positive rate, mindful that different organizations have differing resources to review the findings. + +## Syntactic queries + +These queries are targeting specific names/values and other syntactic traits present in the Solorigate IoCs. They tend to either target syntax that is easy for the malicious actor to alter between operations or syntax that is going to be fairly coincidental, so are either very precise but very fragile, or imprecise but more durable. However, they are very fast to execute, and very easy to modify, so can be easily repurposed to do first pass analysis in future campaigns to hunt for code IoCs. Several of them use a list syntax introduced in CodeQL 1.26, so require that version of newer to compile and execute. + +### cs/Solorigate/number-of-known-commands-in-enum-above-threshold + +**Implemented in:** NumberOfKnownCommandsAboveThreshold.ql + +This query looks for enumerations that look like they are defining Command and Control functionality, based on the enumeration in Solorigate. Enumerations are a convenient way of defining and referencing this functionality, so are likely to be used in other implants. This query does allow some fuzziness to how many commands are defined, by default looking for any enumeration with at least 10 of the 18 commands but is brittle to changes in the names of the commands. + +The specific list of commands it looks for within the enumeration is defined in Solorigate.qll in countSolorigateCommandInEnum. There are several “clusters” of commands – for example, commands to interact with the file system, with the registry, etc. If implementing an API for file system or registry interactions it is possible to coincidentally include similar command names, but it is unlikely a single enumeration would coincidentally contain commands to interact with the file system, assembly, handle process execution, etc. If you know your code performs a subset of those functions, deleting those specific commands from countSolorigateCommandInEnum and lowering the threshold of the query should reduce false positives, though does increase the chance of false negatives. + +This query could be modified to reduce false negatives by decreasing the threshold and changing the name comparisons of the enumeration values to fuzzy matches, but doing so will produce higher false positives. Fuzzy matching is also more computationally costly, so will increase the execution time. + +### cs/Solorigate/number-of-known-hashes-above-threshold + +**Implemented in:** NumberofKnownHashesAboveThreshold.ql + +This query looks for the presence of 5 or more of the XOR’ed hashes Solorigate derived from the names of running processes they wanted to avoid(various anti-malware, etc.). The Solorigate implant would first hash the process name with FNV-1A, and then XOR it with the magic number 6605813339339102567, and then compared to a list of these derived hashes to see if any of the processes the implant wanted to evade were currently running. Likely the reason for the XOR with a magic number is so that comparison values can be unique per implant, so it is very unlikely they were reused elsewhere. However, these values are incredibly unlikely to appear coincidentally in source, so if this query does have findings there is a high probability the findings are malicious. + +The derived hash literals are defined in Solorigate.qll in “solorigateSuspiciousHashes”. If a similar campaign happens in the future this query can easily be repurposed by swapping the current hash values with the values for that campaign. Like now, doing so probably won’t trigger findings as the malicious actor would likely make the values unique per implant, but this is a very quick query to both author/tweak and to execute, so the cost of checking “just in case” is quite low. + +“cs/Solorigate/modified-fnv-function-detection” and “cs/backdoor/process-name-to-hash-function” attempt to detect the actual process name hashing technique rather than the particular values, so will be durable to use of different magic numbers. + +### cs/Solorigate/number-of-known-literals-above-threshold + +**Implemented In:** NumberOfKnownLiteralsAboveThreshold.ql + +This query looks for literals present in the implant, however since many of the literals would appear coincidentally in a great deal of code (common IP addresses, host names, etc.), this query does not fire unless at least 30 of the literals are all present. Many of the literals would need to be reused in other implants if similar functionality were desired (though they could be hidden with a reversable obfuscation technique). + +The query is ensuring that these are semantic literals, so will not incorrectly count usages in comments/method names/variable names/etc. – this shows that even for a relatively simple detection CodeQL provides advantages over more simplistic text parsing. As previously mentioned, many of these literals are incredibly common, so the likelihood that a finding represents malicious modification is low. Its recommended to triage the other queries first, as triaging the results of this query is more labor intensive and results are less likely to represent malicious activity. Reducing the threshold value in NumberOfKnownLiteralsAboveThreshold.ql will increase the chance that it catches other implants that used a subset of the literals, but will also significantly increase false positives. Alternatively, if the first run produces a large number of results, moving the threshold value up helps reduce the findings to only code that more completely mirrors the literals used in Solorigate, while increasing the possibility potential false negatives. + +The list of literals is defined in Solorigate.qll in solorigateSuspiciousLiterals. When run against specific code bases the result set may be more manageable by removing methods and literals known to be legitimately used in that code base, though trimming the list too extensively will increase the chances of false negatives. This query can easily be repurposed for future campaigns by replacing the literals here with the literals that were features of IoCs in those campaigns. If the number of IoC literals is greater in future campaigns, moving the threshold value up from 30 would likely increase detection accuracy without significantly increasing false negative rates. On the flip side, if the number of literals is significantly less, the threshold value will likely need to be decreased from 30. + +### cs/solorigate/number-of-known-method-names-above-threshold + +**Implemented In:** NumberOfKnownMethodNamesAboveThreshold.ql + +This query looks for method names present within the implant, but as with the literals, the method names would appear coincidentally in many code bases as they were intended to blend in. Because the individual method names are highly likely to be coincidentally used, this query only fires if 50 or more are present. This query is ensuring that these are used as method names, so will not incorrectly count usage in literals/comments/variable names/etc. While these are common method names, it would be uncommon (but still possible – we had plenty of false positives) for many of them to all be defined within the same project. Excluding methods that are common overrides in class declarations (ex. ToString) will lower the false positive rate, but with the threshold of 50 we found the result set manageable without that adjustment. + +The list of literals is defined in Solorigate.qll in solorigateSuspiciousMethodNames. While the previous queries looking for the command Enumeration, Derived process hashes, and literals may provide some value if ported to cover other languages, the specific method list for this query does not, as the methods are particular for C#. However, if an additional implant targeting another language is discovered in the future, the basic approach used in this query is re-usable even if the method names are not. + +## Semantic Queries + +The semantic queries are not looking for any specific names or terms unique to the IoCs, but rather techniques or patterns used for the implant’s functionality. Some can be evaded by implementing the functionality via different semantics, but a malicious agent would need to specifically take pains to do so. These queries may detect unrelated backdoors, and can also be ported to cover other programming languages to detect the same techniques in those languages. + +### cs/Solorigate/modified-fnv-function-detection + +**Implemented in:** ModifiedFnvFunctionDetection.ql + +The Solorigate implant tries to evade various security detection software by comparing hashes of the process names against an embedded list of values. However, to make the embedded list unique per implant, the hashes were then XOR’ed with a magic value. The implant embedded a version of the FNV-1A hash function for this purpose, so this query looks for use of an “FNV-like” implementation with XOR. + +The logic that determines what is “FNV-like” is in NonCryptographicHashes.qll, in the predicate “maybeUsedInFNVFunction”. This logic is not looking for specific known implementations of an FNV function, but rather method code that looks like it is trying to implement one of the FNV functions. This should avoid evasions based purely on the name of the function, but deliberate attempts to obfuscate the implementation of the function may be able to evade this analysis. + +Separately, and unrelated to Solorigate, this predicate (as well as the one looking for “Elfhash-like”) can be combined with control flow analysis to ensure that these hash functions are not being used in a cryptographic context where their use would be insecure. + +### cs/backdoor/process-name-to-hash-function + +**Implemented in:** ProcessNameToHashTaintFlow.ql + +This query takes a different approach than the previous two – rather than looking for use of FNV-like methods used specifically in conjunction with an XOR, it instead looks for flow from System.Diagnostics.Process.ProcessName to something that “looks like” a hash function. It determines what looks like a hash function by looking for methods whose names contain “Hash” or MD4/5 or some variation of SHA, or whose implementation is either “FNV-Like” or “Elf-Like” (see NonCryptographicHashes.qll for the logic that determines FNV or Elf-like – looking at the implementation is durable to simple renaming of the methods). This approach should catch a variety of process name hashing schemes, though it should be noted that there are legitimate reasons to hash a process name. The flow analysis is interprocedural, so can detect attempts to obfuscate the hashing of process names by distributing the steps across the source. As the definition of a hash function is intentionally a bit fuzzy this query has a medium precision (i.e. it may falsely catch code that is not attempting to hash the process name), and as there are legitimate reasons to hash a process name the chance that an accurate finding represents a malicious implant is moderate to low depending on the code base. + +To add additional hash detections logic to cast a wider net, modify isGetHash in ProcessNameToHashTaintFlow.ql. + +### cs/backdoor/potential-time-bomb + +**Implemented in:** PotentialTimeBomb.ql + +This query looks for a the Solorigate Implant's time delay functionality. The Backdoor would not initially activate until 12-14 days *after* the Orion update with the implanted code was installed. It did this by checking the last file write time, randomly adding between 288 and 336 hours to it, and comparing that against the current system time before it initially called back to the C2 servers controlling the campaign. This query detects that technique by looking for flow from GetLastWriteTime to an arithmetic operation, and from there to a comparison against the current time. This query will coincidentally flag any software that invokes an action a certain time after installation - for example, prompting the user to register or activate the product after a certain period has elapsed. + +The accuracy of this query could be improved to reduce those coincidental findings by checking if there is then flow to a remote source (which is the case in the Solorigate implant) or to shell or process execution as they are often features of time bombed malicious code, however the additional flow steps do increase the execution time and increase the chance of false negatives. This query as is produced a manageable set of false positives when run across our thousands of databases, so we suggest first running it as is, and only making those modifications if the practice appears to be common in your code bases. + +To make this query more generic, it could be modified to check for other ways of persisting an initial data on the system - reading a registry key, file contents, system reboot time, etc. However, each additional data source will increase false positives. + +### cs/Solorigate/swallow-everything-exception + +**Implemented in:** SwallowEverythingExceptionHandler.ql + +The Solorigate Implant wraps the implanted code in a + + try { + //stuff + } + catch (Exception) {} + +to ensure that runtime exceptions didn’t tip anyone off. This query looks for all catches of generic exceptions, with empty exception blocks. The detection is high precision – it will accurately find all empty generic exception handlers. However, it is unfortunately a common enough bad programming practice that there are plenty of writeups in existence explaining that it is a bad programming practice, so the likelihood of the findings being a malicious implant are low. It’s recommended that they be reviewed to ensure this bad practice isn’t hiding latent (or not so latent) bugs in the code. + +It can be evaded by including any statements in the catch block, but the existing cs/catch-of-all-exceptions query can be used to catch that evasion. That query’s findings will be a superset of this query, as it will catch many legitimate situations where the exception was anticipated and the catch block can take action that would make swallowing the exception and continuing on relatively risk free. By looking at empty catch statements, this query looks for the exact pattern in the Solorigate implant and will generate fewer findings to review. + +### cs/backdoor/dangerous-native-functions + +**Implemented in:** DangerousNativeFunctionCalls.ql + +This query looks for several native Windows API that might be present in backdoor functionality, including several used in Solorigate. It is also more broadly useful in looking for a technique that can be used to evade queries looking for malicious execution of processes by calling the native platform libraries instead of the .Net Class libraries. We are including it to act as inspiration for other query developers to think about how they can query not just for backdoor patterns but also how they can hunt for attempts to then evade those queries. + +While the results of this query are useful on their own, both to cast a wide net to find this evasion technique, and to review why the developers chose the more error prone PInvoke implementation in benign findings, this query was kept simple specifically to use as an example. It can easily be combined with Data Flow or Taint Flow by adding a call to the isExternMethod predicate in DangerousNativeFunctionCalls to an overridden isSink implementation. With this relatively simple addition, flow from untrusted sources like web requests into the potentially dangerous API can easily be detected, and at the very least represent a potential security vulnerability that should be reviewed, but may also represent a C2 implementation attempting to evade searches for the standard Class Library functions. + +## Build CodeQL Databases from the production Build Servers/Pipelines + +The malicious modifications of SolarWinds’ code took place on the build server (more details from [CrowdStrike](https://www.crowdstrike.com/blog/sunspot-malware-technical-analysis/)), so CodeQL databases used for analysis should ideally be built from the same build servers. CodeQL utilizes the same Roslyn Compiler as MSBuild, so absent the malicious actor specifically building checks for the presence of CodeQL, it is likely the injection technique utilized by the malicious actor would replicate when CodeQL was run. Alternatively, if building CodeQL databases in an independent environment, other techniques can be used to validate that the code that was compiled into the final binaries is the same as the source code in the source repository. + +> ### FYI +> +> While the step-by-step details are outside the scope of this ReadMe, if the build environment is configured to perform deterministic builds (not all compilers support this, nor default to this if they do), the binaries produced by the build environment can be compared to binaries produced from the same source compiled in a distinct environment. Additionally, some compilers can be configured to emit a manifest of the source code hashes for the source files that were compiled (MSBuild puts them in the PDB files emitted during compilation), which can be compared to source hashes created in an independent environment. If the comparison of either the deterministically built binaries or source hashes do not match, that is a clear indicator that further investigation is warranted. These two techniques can be automated to provide ongoing validation of the build output. +> +>If comparing source hashes, it is strongly recommended that SHA256 rather than weaker hashes be used. This can be configured in the following Microsoft compilers by using the specified compiler flags below: +> +> * cl.exe /ZH:SHA_256 +> * ml.exe /ZH:SHA_256 +> * ml64.exe /ZH:SHA_256 +> * armasm.exe -gh:SHA_256 +> * armasm64.exe -gh:SHA_256 +> * csc.exe /checksumalgorithm:SHA256 diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.qhelp new file mode 100644 index 00000000000..d3abdc85f28 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.qhelp @@ -0,0 +1,12 @@ + + + +

    The malicious code included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by 6605813339339102567 after computing the FNV-1A.

    +

    This query detects FNV-like hash calculations where there is an additional xor (with any static value) after the hash calculation loop.

    +
    + + + +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql new file mode 100644 index 00000000000..e8e2f42dfe4 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql @@ -0,0 +1,32 @@ +/** + * @name Detects a modified FNV function + * @description Possible indication of Solorigate. Detects a modified FNV1 function, where there is an additional xor using a literal after the regular FNV hash + * @kind problem + * @tags security + * solorigate + * @precision high + * @id cs/solorigate/modified-fnv-function-detection + * @problem.severity error + */ + +import csharp +import Solorigate +import microsoft.code.csharp.Cryptography.NonCryptographicHashes + +from Variable v, Literal l, LoopStmt loop, Expr additional_xor +where maybeUsedInFNVFunction( v, _, _, loop) + and ( + exists( BitwiseXorExpr xor2 | + xor2.getAnOperand() = l and additional_xor = xor2 | + loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() + and xor2.getAnOperand() = v.getAnAccess() + ) or exists( AssignXorExpr xor2 | + xor2.getAnOperand() = l and additional_xor = xor2 | + loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() + and xor2.getAnOperand() = v.getAnAccess() + ) + ) + select l, "The variable $@ seems to be used as part of a FNV-like hash calculation, that is modified by an additional $@ expression using literal $@." + , v, v.toString() + , additional_xor, "xor" + , l, l.toString() diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp new file mode 100644 index 00000000000..0db1732805d --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp @@ -0,0 +1,12 @@ + + + +

    This query detects if there is an enum that includes various of the values used for the Solorigate commands.

    +

    Please notice that by themselves the names of these enum constants are not malign.

    +
    + + + +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql new file mode 100644 index 00000000000..154d115a39f --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql @@ -0,0 +1,20 @@ +/** + * @name Number of Solorigate-related command names in enum is above the threshold + * @description The enum contains several values that look similar to command and control command names, which may indicate that the code may have been tampered by an external agent. + * It is recommended to review the code and verify that there is no unexpected code in this project. + * @kind problem + * @tags security + * solorigate + * @problem.severity warning + * @precision medium + * @id cs/solorigate/number-of-known-commands-in-enum-above-threshold + */ + +import csharp +import Solorigate + +from Enum e, int total +where total = countSolorigateCommandInEnum(e) + and total > 10 +select e, "The enum $@ may be related to Solorigate. It matches " + total + " of the values used for commands in the enum." + , e, e.getName() \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp new file mode 100644 index 00000000000..a5fca70869b --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp @@ -0,0 +1,13 @@ + + + +

    This query detects literals that look like Solorigate Hash values used in the Solorigate code.

    +

    This query detects when the code includes at least 5 of the Hash literals used in the Solorigate tampered code

    +

    Please notice that by themselves these literals are not malign, but several of the values together would be less likely to be coincidental.

    +
    + + + +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql new file mode 100644 index 00000000000..6d4f7818a9e --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql @@ -0,0 +1,23 @@ +/** + * @name Number of Solorigate-related Hashes as literals is above the threshold + * @description The total number of Solorigate-related hash literals found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. + * It is recommended to review the code and verify that there is no unexpected code in this project, however it is highly unlikely the hash values would be present coincideentally + * @kind problem + * @tags security + * solorigate + * @problem.severity warning + * @precision medium + * @id cs/solorigate/number-of-known-hashes-above-threshold + */ + +import csharp +import Solorigate + + +from Literal l, int total, int threshold +where total = countSolorigateSuspiciousHash() + and threshold = 5 // out of ~200 known literals + and isSolorigateHash(l) + and total > threshold +select l, "The Hash literal $@ may be related to the Solorigate campaign. Total count = " + total + " is above the threshold " + threshold + "." + , l, l.getValue() \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp new file mode 100644 index 00000000000..5a275eeadba --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp @@ -0,0 +1,13 @@ + + + +

    This query detects literals used in the Solorigate code.

    +

    This query detects when the code includes at least 30 of the literals used in the Solorigate tampered code

    +

    Please notice that by themselves these literals are not malign.

    +
    + + + +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql new file mode 100644 index 00000000000..d736e6fbf42 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql @@ -0,0 +1,23 @@ +/** + * @name Number of Solorigate-related literals is above the threshold + * @description The total number of Solorigate-related literals found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. + * It is recommended to review the code and verify that there is no unexpected code in this project. + * @kind problem + * @tags security + * solorigate + * @problem.severity warning + * @precision medium + * @id cs/solorigate/number-of-known-literals-above-threshold + */ + +import csharp +import Solorigate + + +from Literal l, int total, int threshold +where total = countSolorigateSuspiciousLiterals() + and threshold = 30 // out of ~150 known literals + and isSolorigateLiteral(l) + and total > threshold +select l, "The literal $@ may be related to the Solorigate campaign. Total count = " + total + " is above the threshold " + threshold + "." + , l, l.getValue() \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp new file mode 100644 index 00000000000..9216fa9e2e5 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp @@ -0,0 +1,13 @@ + + + +

    This query detects method names used in the Solorigate code.

    +

    This query detects when the code includes at least 50 of the mthods used in the Solorigate tampered code

    +

    Please notice that by themselves these method names are not malign.

    +
    + + + +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql new file mode 100644 index 00000000000..f38a2f2dfb8 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql @@ -0,0 +1,23 @@ +/** + * @name Number of Solorigate-related method names is above the threshold + * @description The total number of Solorigate-related method names found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. + * It is recommended to review the code and verify that there is no unexpected code in this project. + * @kind problem + * @tags security + * solorigate + * @problem.severity warning + * @precision medium + * @id cs/solorigate/number-of-known-method-names-above-threshold + */ + +import csharp +import Solorigate + + +from Method m, int total, int threshold +where total = countSolorigateSuspiciousMethodNames() + and threshold = 50 // out of ~ 100 known names + and isSolorigateSuspiciousMethodName(m) + and total > threshold +select m, "The method $@ may be related to Solorigate. Total count = " + total + " is above the threshold " + threshold + "." + , m, m.getName() \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp new file mode 100644 index 00000000000..798ae65ba8b --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp @@ -0,0 +1,13 @@ + + + +

    The nation-state supply chain attack on SolarWinds known as Solorigate or SunBurst gave nation-state actors access to some victims' networks.

    +

    The purpose of these rules is to identify poetntially tampered code that requires further analysis

    +
    + +

    Any findings from these rules are only intended to indicate suspicious code that shares similarities with known portions of code used for this attack, but no certainty that the code is related or part of any attack.

    +

    For more information, please visit https://aka.ms/solorigate.

    +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll new file mode 100644 index 00000000000..77cd4c0fe2e --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll @@ -0,0 +1,163 @@ +/* * + * Provides reusable predicates related to Solorigate + * + */ + +import csharp + +/* + * Returns a list of Literals representing process hashes. These are unlikely to be recycled between campaigns, so not expected to have hits, but if present + * are almost certainly an indicator of compromise + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * and https://github.com/fireeye/sunburst_countermeasures/blob/main/fnv1a_xor_hashes.txt + */ +private string solorigateSuspiciousHashes() { + result = [ + "10063651499895178962", "10235971842993272939", "10296494671777307979", "10336842116636872171", "10374841591685794123", "10393903804869831898", "10463926208560207521", + "10484659978517092504", "10501212300031893463", "10545868833523019926", "10657751674541025650", "106672141413120087", "10734127004244879770", "10829648878147112121", + "1099511628211", "11073283311104541690", "1109067043404435916", "11109294216876344399", "11266044540366291518", "11385275378891906608", "11771945869106552231", "11801746708619571308", + "11818825521849580123", "11913842725949116895", "12027963942392743532", "12094027092655598256", "12343334044036541897", "12445177985737237804", "12445232961318634374", + "12574535824074203265", "12679195163651834776", "12709986806548166638", "12718416789200275332", "12785322942775634499", "12790084614253405985", "12969190449276002545", + "13014156621614176974", "13029357933491444455", "13135068273077306806", "13260224381505715848", "13316211011159594063", "13464308873961738403", "13544031715334011032", + "13581776705111912829", "13599785766252827703", "13611051401579634621", "13611814135072561278", "13655261125244647696", "1367627386496056834", "1368907909245890092", "13693525876560827283", + "13783346438774742614", "13799353263187722717", "13825071784440082496", "13852439084267373191", "13876356431472225791", "14055243717250701608", "14079676299181301772", "14095938998438966337", + "14111374107076822891", "14193859431895170587", "14226582801651130532", "14243671177281069512", "14256853800858727521", "14480775929210717493", "14482658293117931546", + "14513577387099045298", "14630721578341374856", "14695981039346656037", "14710585101020280896", "1475579823244607677", "14868920869169964081", "14968320160131875803", "14971809093655817917", + "15039834196857999838", "15092207615430402812", "15114163911481793350", "15194901817027173566", "15267980678929160412", "15457732070353984570", "15514036435533858158", + "15535773470978271326", "15587050164583443069", "155978580751494388", "15695338751700748390", "15997665423159927228", "16066522799090129502", "16066651430762394116", "16112751343173365533", + "16130138450758310172", "1614465773938842903", "16292685861617888592", "16335643316870329598", "16423314183614230717", "16570804352575357627", "1682585410644922036", "16858955978146406642", + "16990567851129491937", "17017923349298346219", "17097380490166623672", "17109238199226571972", "17204844226884380288", "17291806236368054941", "17351543633914244545", + "17439059603042731363", "17574002783607647274", "17624147599670377042", "17633734304611248415", "17683972236092287897", "17849680105131524334", "17939405613729073960", "17956969551821596225", + "17978774977754553159", "17984632978012874803", "17997967489723066537", "18147627057830191163", "18150909006539876521", "18159703063075866524", "18246404330670877335", + "18294908219222222902", "18392881921099771407", "18446744073709551613", "191060519014405309", "2032008861530788751", + "2128122064571842954", "2147483647", "2147745794", "2380224015317016190", "2478231962306073784", "2532538262737333146", + "2589926981877829912", "2597124982561782591", "2600364143812063535", "2717025511528702475", "2734787258623754862", "27407921587843457", "2760663353550280147", + "2797129108883749491", "2810460305047003196", "292198192373389586", "2934149816356927366", "3045986759481489935", "3178468437029279937", "3200333496547938354", "3320026265773918739", + "3320767229281015341", "3341747963119755850", "3407972863931386250", "3413052607651207697", "3413886037471417852", "3421197789791424393", "3421213182954201407", "3425260965299690882", + "3538022140597504361", "3575761800716667678", "3588624367609827560", "3626142665768487764", "3642525650883269872", "3656637464651387014", "3660705254426876796", "3769837838875367802", + "3778500091710709090", "3796405623695665524", "3869935012404164040", "3890769468012566366", "3890794756780010537", "397780960855462669", "4030236413975199654", "4088976323439621041", + "4454255944391929578", "4501656691368064027", "4578480846255629462", "4821863173800309721", "4931721628717906635", "506634811745884560", "5132256620104998637", + "5183687599225757871", "521157249538507889", "5219431737322569038", "541172992193764396", "5415426428750045503", "5449730069165757263", "5587557070429522647", "5614586596107908838", + "576626207276463000", "5942282052525294911", "5945487981219695001", "5984963105389676759", "607197993339007484", + "6088115528707848728", "6116246686670134098", "6180361713414290679", "6195833633417633900", "6274014997237900919", "640589622539783622", "6461429591783621719", "6491986958834001955", + "6508141243778577344", "6605813339339102567", "682250828679635420", "6827032273910657891", "6943102301517884811", "700598796416086955", "7080175711202577138", + "7175363135479931834", "7315838824213522000", "7412338704062093516", "7516148236133302073", "7574774749059321801", "7701683279824397773", "7775177810774851294", "7810436520414958497", + "7878537243757499832", "79089792725215063", "7982848972385914508", "8052533790968282297", "8129411991672431889", "8146185202538899243", "835151375515278827", "8381292265993977266", + "8408095252303317471", "8473756179280619170", "8478833628889826985", "8612208440357175863", "8697424601205169055", "8698326794961817906", "8709004393777297355", "8727477769544302060", + "8760312338504300643", "8799118153397725683", "8873858923435176895", "8994091295115840290", "9007106680104765185", "9061219083560670602", "9149947745824492274", "917638920165491138", "9234894663364701749", + "9333057603143916814", "9384605490088500348", "9531326785919727076", "9555688264681862794", "9559632696372799208", "9903758755917170407" + ] + +} + +/* + * Holds if the literal is one that matches a literal found in Solorigate code. + * + * NOTE: Some of the values have been commented out as they are commonly found elsewhere. + */ +predicate isSolorigateHash(Literal l){ + l.getValue() = solorigateSuspiciousHashes() +} + +/* + * Returns the total number of Solorigate-related literales found in the project + */ +int countSolorigateSuspiciousHash(){ + result = count(string s | exists( Literal l | s = l.getValue() and s = solorigateSuspiciousHashes())) +} + +/* + * Returns a list of Literals used by Solorigate + * + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * and https://github.com/fireeye/sunburst_countermeasures/blob/main/fnv1a_xor_hashes.txt + */ +private string solorigateSuspiciousLiterals() { + result = [ "(?i)([^a-z]|^)(test)([^a-z]|$)", "(?i)(solarwinds)", "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n", "[{0,5}] {1}\n", "[E] {0} {1} {2}", + "\"\\{[0-9a-f-]{36}\\}\"|\"[0-9a-f]{32}\"|\"[0-9a-f]{16}\"", ".CortexPlugin", ".Orion", "\"EventName\":\"EventManager\",", "\"EventType\":\"Orion\",", + "\\OrionImprovement\\SolarWinds.OrionImprovement.exe", "0123456789abcdefghijklmnopqrstuvwxyz-_.", + "\"sessionId\":\"{0}\",", "\"steps\":[", "\"Succeeded\":true,", "\"Timestamp\":\"\\/Date({0})\\/\",", "\"userId\":\"{0}\",", "{0} {1} HTTP/{2}\n", + "10140", "144.86.226.0", "154.118.140.0", "172.16.0.0", "18.130.0.0", "184.72.0.0", "192.168.0.0", "199.201.117.0", "20.140.0.0", "20100", "20220", "217.163.7.0", "224.0.0.0", + "240.0.0.0", "255.240.0.0", "255.254.0.0", "255.255.248.0", "3.0.0.382", "41.84.159.0", "43140", "4320", "43260", "524287", "583da945-62af-10e8-4902-a8f205c72b2e", "65280", + "71.152.53.0", "74.114.24.0", "8.18.144.0", "87.238.80.0", "96.31.172.0", "983040", "99.79.0.0", + "Administrator", "advapi32.dll", "Apollo", "appsync-api", "avsvmcloud.com", "api.solarwinds.com", "-root", "-cert", "-universal_ca", "-ca", "-primary_ca", "-timestamp", "-global", "-secureca", "CloudMonitoring", + "MACAddress", "DHCPEnabled", "DHCPServer", "DNSHostName", "DNSDomainSuffixSearchOrder", "DNSServerSearchOrder", "IPAddress", "IPSubnet", "DefaultIPGateway", "OSArchitecture", "InstallDate", "Organization", "RegisteredUser", + "fc00::", "fe00::", "fec0::", "ffc0::", "ff00::", + "HKCC", "HKCR", "HKCU", "HKDD", "HKEY_CLASSES_ROOT", "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA", "HKEY_LOCAL_MACHINE", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography", + "HKEY_PERFOMANCE_DATA", "HKEY_USERS", "HKLM", "HKPD", "HKU", "If-None-Match", "Microsoft-CryptoAPI/", "Nodes", "Volumes", "Interfaces", "Components", + "opensans", "Organization", "OSArchitecture", "ParentProcessID", "PathName", "ReportWatcherPostpone", "ReportWatcherRetry", "S-1-5-", "SeRestorePrivilege", "SeShutdownPrivilege", "SeTakeOwnershipPrivilege", + "SolarWinds", "SolarWindsOrionImprovementClient/", "SourceCodePro", "SourceHanSans", "SourceHanSerif", "SourceSerifPro", "Start", "swip/Events", "swip/upd/", "swip/Upload.ashx", "SYSTEM", + "SYSTEM\\CurrentControlSet\\services", "us-east-1", "us-east-2", "us-west-2", + "fonts/woff/{0}-{1}-{2}{3}.woff2", "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2", "ph2eifo3n5utg1j8d94qrvbmk0sal76c", "pki/crl/{0}{1}{2}.crl", "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj", + "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true", "Select * From Win32_OperatingSystem", "Select * From Win32_Process", "Select * From Win32_SystemDriver", "Select * From Win32_UserAccount"] + +} + +/* + * Holds if the literal is one that matches a literal found in Solorigate code. + * + * NOTE: Some of the values have been commented out as they are commonly found elsewhere. + */ +predicate isSolorigateLiteral(Literal l){ + l.getValue() = solorigateSuspiciousLiterals() +} + +/* + * Returns the total number of Solorigate-related literales found in the project + */ +int countSolorigateSuspiciousLiterals(){ + result = count(string s | exists( Literal l | s = l.getValue() and s = solorigateSuspiciousLiterals())) +} + +/* + * Returns a list of method names used by Solorigate + * + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + */ +private string solorigateSuspiciousMethodNames() { + result = [ "Abort", "AddFileExecutionEngine", "AddRegistryExecutionEngine", "AdjustTokenPrivileges", "Base64Decode", "Base64Encode", "ByteArrayToHexString", "CheckServerConnection", "Close", "CloseHandle", "CollectSystemDescription", + "Compress", "CreateSecureString", "CreateString", "CreateUploadRequest", "CreateUploadRequestImpl", "Decompress", "DecryptShort", "Deflate", "DelayMin", "DelayMs", "DeleteFile", "DeleteRegistryValue", "DeleteValue", + "ExecuteEngine", "FileExists", "GetAddresses", "GetAddressFamily", "GetArgumentIndex", "GetBaseUri", "GetBaseUriImpl", "GetCache", "GetCurrentProcess", "GetCurrentString", "GetDescriptionId", "GetFileHash", "GetFileSystemEntries", + "GetHash", "GetHive", "GetIntArray", "GetIPHostEntry", "GetManagementObjectProperty", "GetNetworkAdapterConfiguration", "GetNewOwnerName", "GetNextString", "GetNextStringEx", "GetOrCreateUserID", "GetOrionImprovementCustomerId", + "GetOSVersion", "GetPreviousString", "GetProcessByDescription", "GetRegistrySubKeyAndValueNames", "GetStatus", "GetStringHash", "GetSubKeyAndValueNames", "GetUserAgent", "GetValue", "GetWebProxy", "HexStringToByteArray", "Inflate", + "Initialize", "InitiateSystemShutdownExW", "IsNullOrInvalidName", "IsSynchronized", "KillTask", "LookupPrivilegeValueW", "OpenProcessToken", "ParseServiceResponse", "Quote", "ReadConfig", "ReadDeviceInfo", "ReadRegistryValue", + "ReadReportStatus", "ReadServiceStatus", "RebootComputer", "RunTask", "SearchAssemblies", "SearchConfigurations", "SearchServices", "SetAutomaticMode", "SetKeyOwner", "SetKeyOwnerWithPrivileges", "SetKeyPermissions", "SetManualMode", + "SetProcessPrivilege", "SetRegistryValue", "SetTime", "SetValue", "SplitString", "ToString", "TrackEvent", "TrackProcesses", "Unquote", "Unzip", "Update", "UpdateBuffer", "UpdateNotification", "UploadSystemDescription", "Valid", + "WriteConfig", "WriteFile", "WriteReportStatus", "WriteServiceStatus", "Zip"] +} + +/* + * Holds if the method is one that matches a method found in Solorigate code. + * + * NOTE: Pretty much all of these method names are common. + */ +predicate isSolorigateSuspiciousMethodName(Method m) { + m.fromSource() and + ( + m.getName() = solorigateSuspiciousMethodNames() + + ) +} + +/* + * Returns the total number of Solorigate-related method names found in the project + */ +int countSolorigateSuspiciousMethodNames(){ + result = count(string s | exists(Method m | s=m.getName() and s = solorigateSuspiciousMethodNames())) +} + + +/* + * Returns the total number of Solorigate-related commands in the given enum + * + * This command list is described at https://www.fireeye.com/blog/products-and-services/2020/12/global-intrusion-campaign-leverages-software-supply-chain-compromise.html + * and the enum names are based from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + */ +int countSolorigateCommandInEnum(Enum e) { + result = count(string s, EnumConstant ec | + e.getAnEnumConstant() = ec and + s = ec.getName() and + s in [ "Idle", "Exit", "SetTime", "CollectSystemDescription", "UploadSystemDescription", "RunTask", "GetProcessByDescription", "KillTask", + "GetFileSystemEntries", "WriteFile", "FileExists", "DeleteFile", "GetFileHash", "ReadRegistryValue", "SetRegistryValue", + "DeleteRegistryValue", "GetRegistrySubKeyAndValueNames", "Reboot", "None" ] ) +} diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp new file mode 100644 index 00000000000..83fa8f8c58c --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp @@ -0,0 +1,12 @@ + + + +

    The malicious code was wrapped in generic exception catch blocks that lacked any statements

    +

    This query detects all generic exception empty catch blocks, but it is strongly suggested that the results for cs/catch-of-all-exceptions also be reviewed in the event that a malicious swallow everything exception handler was not empty

    +
    + + + +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql new file mode 100644 index 00000000000..f481956883c --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql @@ -0,0 +1,30 @@ +/** + * @name Looks for use of a Swallow Everything empty catch block + * @description Possible indication of Solorigate. The maliciously inserted source was wrapped in a Swallow Everything catch to hide any runtime exceptions + * @kind problem + * @tags security + * solorigate + * @precision high + * @id cs/solorigate/swallow-everything-exception + * @problem.severity error + */ + +import csharp +import Solorigate +import semmle.code.csharp.frameworks.System + +class GenericCatchClause extends CatchClause { + GenericCatchClause() { + this instanceof GeneralCatchClause + or + this = + any(SpecificCatchClause scc | + scc.getCaughtExceptionType() instanceof SystemExceptionClass and + not scc.hasFilterClause() + ) + } +} + +from GenericCatchClause gcc +where gcc.getBlock().getNumberOfStmts() = 0 +select gcc, "Empty Swallow Everything Exception." diff --git a/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll new file mode 100644 index 00000000000..4f611bac84b --- /dev/null +++ b/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -0,0 +1,108 @@ +/* * + * Predicates that help detect potential non-cryptographic hash functions + * + * By themselves, non-cryptographic functions are common and not dangerous + * These predicates are intended for helping detect non-cryptographic hashes that may be used + * in a context that is not appropriate, or for detecting modified hash functions + */ + +import csharp +private import DataFlow +private import semmle.code.csharp.dataflow.TaintTracking2 + +predicate maybeANonCryptogrphicHash( Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop ) { + callable = loop.getEnclosingCallable() and + ( + maybeUsedInFNVFunction( v, xor, mul, loop) or + maybeUsedInElfHashFunction( v, xor, mul, loop) + ) +} + +/** + * Holds if the arguments are used in a way that resembles a FNV hash function + * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression + * followed by a multiplication `mul` expression. + */ +predicate maybeUsedInFNVFunction( Variable v, Expr xor, Expr mul, LoopStmt loop) { + exists( Expr e1, Expr e2 | + exists( Operation axore, Operation amule | + xor = axore and mul = amule | + e1.getAChild*() = v.getAnAccess() and + e2.getAChild*() = v.getAnAccess() and + e1 = axore.getAnOperand() and + e2 = amule.getAnOperand() and + axore.getAControlFlowNode().getASuccessor*() = amule.getAControlFlowNode() and + (axore instanceof AssignXorExpr or axore instanceof BitwiseXorExpr) and + (amule instanceof AssignMulExpr or amule instanceof MulExpr) + ) + ) + and loop.getAChild*() = mul.getEnclosingStmt() + and loop.getAChild*() = xor.getEnclosingStmt() +} + +/** + * Holds if the arguments are used in a way that resembles an Elf-Hash hash function + * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression + * followed by an addition `add` expression. + */ +predicate maybeUsedInElfHashFunction(Variable v, Expr xorExpr, Expr addExpr, LoopStmt loop) { + exists( Expr e1, Operation add, Expr e2, AssignExpr addAssign, Operation xor, AssignExpr xorAssign, Operation notOp, AssignExpr notAssign | + xorExpr = xor and + addExpr = add and + ( add instanceof AddExpr or add instanceof AssignAddExpr ) and + e1.getAChild*() = add.getAnOperand() and + e1 instanceof BinaryBitwiseOperation and + e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and + v = addAssign.getTargetVariable() and + addAssign.getAChild*() = add and + ( xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr ) and + addAssign.getAControlFlowNode().getASuccessor*() = xor.getAControlFlowNode() and + xorAssign.getAChild*() = xor and + v = xorAssign.getTargetVariable() and + (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation ) and + xor.getAControlFlowNode().getASuccessor*() = notOp.getAControlFlowNode() and + notAssign.getAChild*() = notOp and + v = notAssign.getTargetVariable() and + loop.getAChild*() = add.getEnclosingStmt() and + loop.getAChild*() = xor.getEnclosingStmt() + ) +} + +/** + * Any dataflow from any source to any sink, used internally + */ +private class AnyDataFlow extends TaintTracking2::Configuration { + AnyDataFlow() { + this = "DataFlowFromDataGatheringMethodToVariable" + } + + override predicate isSource(Node source) { + any() + } + + override predicate isSink(Node sink) + { + any() + } +} + +/** + * Holds if the Callable is a function that behaves like a non-cryptographic hash + * where the parameter `param` is likely the message to hash + */ +predicate isCallableAPotentialNonCryptographicHashFunction( Callable callable, Parameter param) { + exists( Variable v, Expr op1, Expr op2, LoopStmt loop | + maybeANonCryptogrphicHash(callable, v, op1, op2, loop) + and callable.getAParameter() = param + and ( + param.getAnAccess() = op1.(Operation).getAnOperand().getAChild*() or + param.getAnAccess() = op2.(Operation).getAnOperand().getAChild*() or + exists( AnyDataFlow config, Node source, Node sink | + ( sink.asExpr() = op1.(Operation).getAChild*() or + sink.asExpr() = op2.(Operation).getAChild*()) and + source.asExpr() = param.getAnAccess() and + config.hasFlow(source, sink) + ) + ) + ) +} From 86a2aa97ec4053740182347f19408032b900b62c Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Wed, 3 Feb 2021 15:48:16 -0800 Subject: [PATCH 103/429] Fixing incorrect file extension & adding suite --- csharp/ql/src/codeql-suites/solorigate.qls | 4 ++++ ...eFunctionCall.qlhelp => DangerousNativeFunctionCall.qhelp} | 0 ...oHashTaintFlow.qlhelp => ProcessNameToHashTaintFlow.qhelp} | 0 3 files changed, 4 insertions(+) create mode 100644 csharp/ql/src/codeql-suites/solorigate.qls rename csharp/ql/src/experimental/Security Features/backdoor/{DangerousNativeFunctionCall.qlhelp => DangerousNativeFunctionCall.qhelp} (100%) rename csharp/ql/src/experimental/Security Features/backdoor/{ProcessNameToHashTaintFlow.qlhelp => ProcessNameToHashTaintFlow.qhelp} (100%) diff --git a/csharp/ql/src/codeql-suites/solorigate.qls b/csharp/ql/src/codeql-suites/solorigate.qls new file mode 100644 index 00000000000..f6e575bb700 --- /dev/null +++ b/csharp/ql/src/codeql-suites/solorigate.qls @@ -0,0 +1,4 @@ +- description: Queries related to Solorigate +- qlpack: codeql-csharp +- include: + tags contain: solorigate diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlhelp b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp similarity index 100% rename from csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlhelp rename to csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlhelp b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp similarity index 100% rename from csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlhelp rename to csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp From 53ab787efc28a07949ad08cbcef203023fd8ad3b Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Wed, 3 Feb 2021 15:54:47 -0800 Subject: [PATCH 104/429] Fixed format --- .../backdoor/DangerousNativeFunctionCall.ql | 23 +- .../backdoor/PotentialTimeBomb.ql | 157 +++++---- .../backdoor/ProcessNameToHashTaintFlow.ql | 44 ++- .../Solorigate/ModifedFnvFunctionDetection.ql | 32 +- .../NumberOfKnownCommandsAboveThreshold.ql | 12 +- .../NumberOfKnownHashesAboveThreshold.ql | 17 +- .../NumberOfKnownLiteralsAboveThreshold.ql | 17 +- .../NumberOfKnownMethodNamesAboveThreshold.ql | 17 +- .../campaign/Solorigate/Solorigate.qll | 331 +++++++++++------- .../Cryptography/NonCryptographicHashes.qll | 141 ++++---- 10 files changed, 436 insertions(+), 355 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql index cbc42c41ddb..cc8f0bda367 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql @@ -20,34 +20,35 @@ predicate isDangerousMethod(Method m) { m.getName().matches("LogonUser%") or m.getName().matches("WNetAddConnection%") or m.getName() = "DeviceIoControl" or - m.getName().matches ("LoadLibrary%") or + m.getName().matches("LoadLibrary%") or m.getName() = "GetProcAddress" or - m.getName().matches ("CreateProcess%") or - m.getName().matches ("InitiateSystemShutdown%") or + m.getName().matches("CreateProcess%") or + m.getName().matches("InitiateSystemShutdown%") or m.getName() = "GetCurrentProcess" or m.getName() = "GetCurrentProcessToken" or m.getName() = "GetCurrentThreadToken" or m.getName() = "GetCurrentThreadEffectiveToken" or m.getName() = "OpenThreadToken" or m.getName() = "SetTokenInformation" or - m.getName().matches ("LookupPrivilegeValue%") or + m.getName().matches("LookupPrivilegeValue%") or m.getName() = "AdjustTokenPrivileges" or m.getName() = "SetProcessPrivilege" or m.getName() = "ImpersonateLoggedOnUser" or - m.getName().matches ("Add%Ace%") + m.getName().matches("Add%Ace%") } predicate isExternMethod(Method externMethod) { externMethod.isExtern() or externMethod.getAnAttribute().getType() instanceof - SystemRuntimeInteropServicesDllImportAttributeClass + SystemRuntimeInteropServicesDllImportAttributeClass or externMethod.getDeclaringType().getAnAttribute().getType() instanceof - SystemRuntimeInteropServicesComImportAttributeClass + SystemRuntimeInteropServicesComImportAttributeClass } - + from MethodCall mc -where isExternMethod(mc.getTarget()) -and isDangerousMethod(mc.getTarget()) -select mc, "Call to an external method $@", mc, mc.toString() \ No newline at end of file +where + isExternMethod(mc.getTarget()) and + isDangerousMethod(mc.getTarget()) +select mc, "Call to an external method $@", mc, mc.toString() diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql index 367ec6955e2..3c83c0145f0 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -14,140 +14,139 @@ import DataFlow /** * Class that will help to find the source for the trigger file-modification date. - * + * * May be extended as new patterns for similar time bombs are found. */ class GetLastWriteTimeMethod extends Method { - GetLastWriteTimeMethod() { - this.getQualifiedName() in [ "System.IO.File.GetLastWriteTime", "System.IO.File.GetFileCreationTime", "System.IO.File.GetCreationTimeUtc", "System.IO.File.GetLastAccessTimeUtc" ] - } + GetLastWriteTimeMethod() { + this.getQualifiedName() in [ + "System.IO.File.GetLastWriteTime", "System.IO.File.GetFileCreationTime", + "System.IO.File.GetCreationTimeUtc", "System.IO.File.GetLastAccessTimeUtc" + ] + } } /** * Abstracts `System.DateTime` structure */ class DateTimeStruct extends Struct { - DateTimeStruct() { - this.getQualifiedName() = "System.DateTime" - } - - /** - * holds if the Callable is used for DateTime arithmetic operations - */ - Callable getATimeSpanArtithmeticCallable() { - ( result = this.getAnOperator() or result = this.getAMethod()) and - ( result.getName() in ["Add", "AddDays", "AddHours", "AddMilliseconds", "AddMinutes", "AddMonths", "AddSeconds", "AddTicks", "AddYears", "+", "-"] ) - } + DateTimeStruct() { this.getQualifiedName() = "System.DateTime" } - /** - * Holds if the Callable is used for DateTime comparision - */ - Callable getAComparisonCallable() { - ( result = this.getAnOperator() or result = this.getAMethod()) and - ( result.getName() in ["Compare", "CompareTo", "Equals", "==", "!=", "<", ">", "<=", ">="] ) - } + /** + * holds if the Callable is used for DateTime arithmetic operations + */ + Callable getATimeSpanArtithmeticCallable() { + (result = this.getAnOperator() or result = this.getAMethod()) and + result.getName() in [ + "Add", "AddDays", "AddHours", "AddMilliseconds", "AddMinutes", "AddMonths", "AddSeconds", + "AddTicks", "AddYears", "+", "-" + ] + } + + /** + * Holds if the Callable is used for DateTime comparision + */ + Callable getAComparisonCallable() { + (result = this.getAnOperator() or result = this.getAMethod()) and + result.getName() in ["Compare", "CompareTo", "Equals", "==", "!=", "<", ">", "<=", ">="] + } } /** - * Dataflow configuration to find flow from a GetLastWriteTime source to a DateTime arithmetic operation + * Dataflow configuration to find flow from a GetLastWriteTime source to a DateTime arithmetic operation */ private class FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable extends TaintTracking::Configuration { FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable() { this = "FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable" } - override - predicate isSource(DataFlow::Node source) { - exists( Call call, GetLastWriteTimeMethod m | - m.getACall() = call and - source.asExpr() = call + override predicate isSource(DataFlow::Node source) { + exists(Call call, GetLastWriteTimeMethod m | + m.getACall() = call and + source.asExpr() = call ) } - override - predicate isSink(DataFlow::Node sink) { - exists( Call call, DateTimeStruct dateTime | - call.getAChild*() = sink.asExpr() and - call = dateTime.getATimeSpanArtithmeticCallable().getACall() + override predicate isSink(DataFlow::Node sink) { + exists(Call call, DateTimeStruct dateTime | + call.getAChild*() = sink.asExpr() and + call = dateTime.getATimeSpanArtithmeticCallable().getACall() ) } } /** - * Dataflow configuration to find flow from a DateTime arithmetic operation to a DateTime comparison operation + * Dataflow configuration to find flow from a DateTime arithmetic operation to a DateTime comparison operation */ private class FlowsFromTimeSpanArithmeticToTimeComparisonCallable extends TaintTracking::Configuration { FlowsFromTimeSpanArithmeticToTimeComparisonCallable() { this = "FlowsFromTimeSpanArithmeticToTimeComparisonCallable" } - override - predicate isSource(DataFlow::Node source) { - exists( DateTimeStruct dateTime, Call call | - source.asExpr() = call | - call = dateTime.getATimeSpanArtithmeticCallable().getACall() + override predicate isSource(DataFlow::Node source) { + exists(DateTimeStruct dateTime, Call call | source.asExpr() = call | + call = dateTime.getATimeSpanArtithmeticCallable().getACall() ) } - override - predicate isSink(DataFlow::Node sink) { - exists( Call call, DateTimeStruct dateTime | - call.getAnArgument().getAChild*() = sink.asExpr() and - call = dateTime.getAComparisonCallable().getACall() + override predicate isSink(DataFlow::Node sink) { + exists(Call call, DateTimeStruct dateTime | + call.getAnArgument().getAChild*() = sink.asExpr() and + call = dateTime.getAComparisonCallable().getACall() ) - } } /** - * Dataflow configuration to find flow from a DateTime comparison operation to a Selection Statement (such as an If) + * Dataflow configuration to find flow from a DateTime comparison operation to a Selection Statement (such as an If) */ private class FlowsFromTimeComparisonCallableToSelectionStatementCondition extends TaintTracking::Configuration { FlowsFromTimeComparisonCallableToSelectionStatementCondition() { this = "FlowsFromTimeComparisonCallableToSelectionStatementCondition" } - override - predicate isSource(DataFlow::Node source) { - exists( DateTimeStruct dateTime, Call call | - source.asExpr() = call | - call = dateTime.getAComparisonCallable().getACall() + override predicate isSource(DataFlow::Node source) { + exists(DateTimeStruct dateTime, Call call | source.asExpr() = call | + call = dateTime.getAComparisonCallable().getACall() ) } - override - predicate isSink(DataFlow::Node sink) { - exists( SelectionStmt sel | - sel.getCondition().getAChild*() = sink.asExpr() - ) - + override predicate isSink(DataFlow::Node sink) { + exists(SelectionStmt sel | sel.getCondition().getAChild*() = sink.asExpr()) } } /** * Holds if the last file modification date from the call to getLastWriteTimeMethodCall will be used in a DateTime arithmetic operation timeArithmeticCall, - * which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger + * which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger */ -predicate isPotentialTimeBomb( Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement ) { - exists( FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable config1, Node sink, DateTimeStruct dateTime, - FlowsFromTimeSpanArithmeticToTimeComparisonCallable config2, Node sink2, - FlowsFromTimeComparisonCallableToSelectionStatementCondition config3, Node sink3 | - config1.hasFlow(exprNode(getLastWriteTimeMethodCall), sink) and - timeArithmeticCall = dateTime.getATimeSpanArtithmeticCallable().getACall() and - timeArithmeticCall.getAChild*() = sink.asExpr() and - config2.hasFlow(exprNode(timeArithmeticCall), sink2) and - timeComparisonCall = dateTime.getAComparisonCallable().getACall() and - timeComparisonCall.getAnArgument().getAChild*() = sink2.asExpr() and - config3.hasFlow(exprNode(timeComparisonCall), sink3) and - selStatement.getCondition().getAChild*() = sink3.asExpr() - ) +predicate isPotentialTimeBomb( + Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, + SelectionStmt selStatement +) { + exists( + FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable config1, Node sink, + DateTimeStruct dateTime, FlowsFromTimeSpanArithmeticToTimeComparisonCallable config2, + Node sink2, FlowsFromTimeComparisonCallableToSelectionStatementCondition config3, Node sink3 + | + config1.hasFlow(exprNode(getLastWriteTimeMethodCall), sink) and + timeArithmeticCall = dateTime.getATimeSpanArtithmeticCallable().getACall() and + timeArithmeticCall.getAChild*() = sink.asExpr() and + config2.hasFlow(exprNode(timeArithmeticCall), sink2) and + timeComparisonCall = dateTime.getAComparisonCallable().getACall() and + timeComparisonCall.getAnArgument().getAChild*() = sink2.asExpr() and + config3.hasFlow(exprNode(timeComparisonCall), sink3) and + selStatement.getCondition().getAChild*() = sink3.asExpr() + ) } -from Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement -where isPotentialTimeBomb( getLastWriteTimeMethodCall, timeArithmeticCall, timeComparisonCall, selStatement ) -select selStatement, "Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger." - , timeComparisonCall, timeComparisonCall.toString() - , timeArithmeticCall, "an offset" - ,getLastWriteTimeMethodCall, "last modification time of a file" - - +from + Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, + SelectionStmt selStatement +where + isPotentialTimeBomb(getLastWriteTimeMethodCall, timeArithmeticCall, timeComparisonCall, + selStatement) +select selStatement, + "Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger.", + timeComparisonCall, timeComparisonCall.toString(), timeArithmeticCall, "an offset", + getLastWriteTimeMethodCall, "last modification time of a file" diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql index 63085f75ddc..4b1c657eff3 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -14,44 +14,42 @@ import DataFlow import microsoft.code.csharp.Cryptography.NonCryptographicHashes class DataFlowFromMethodToHash extends TaintTracking::Configuration { - DataFlowFromMethodToHash() { - this = "DataFlowFromMethodNameToHashFunction" - } + DataFlowFromMethodToHash() { this = "DataFlowFromMethodNameToHashFunction" } + /** * Holds if `source` is a relevant data flow source. */ - override predicate isSource(Node source) - { - isSuspiciousPropertyName(source.asExpr()) - } + override predicate isSource(Node source) { isSuspiciousPropertyName(source.asExpr()) } /** * Holds if `sink` is a relevant data flow sink. */ - override predicate isSink(Node sink) - { - isGetHash(sink.asExpr()) - } + override predicate isSink(Node sink) { isGetHash(sink.asExpr()) } } predicate isGetHash(Expr arg) { - exists (MethodCall mc | - (mc.getTarget().getName().matches ("%Hash%") or - mc.getTarget().getName().regexpMatch("Md[4-5]|Sha[1-9]{1,3}") + exists(MethodCall mc | + ( + mc.getTarget().getName().matches("%Hash%") or + mc.getTarget().getName().regexpMatch("Md[4-5]|Sha[1-9]{1,3}") + ) and + mc.getAnArgument() = arg + ) + or + exists(Callable callable, Parameter param, Call call, int i | + isCallableAPotentialNonCryptographicHashFunction(callable, param) and + callable.getParameter(i) = param and + call = callable.getACall() and + call.getArgument(i) = arg ) - and - mc.getAnArgument() = arg) or - exists( Callable callable, Parameter param, Call call, int i | - isCallableAPotentialNonCryptographicHashFunction( callable, param ) and - callable.getParameter(i) = param and - call = callable.getACall() and - call.getArgument(i) = arg) } predicate isSuspiciousPropertyName(PropertyRead pr) { - pr.getTarget().getQualifiedName() = "System.Diagnostics.Process.ProcessName" + pr.getTarget().getQualifiedName() = "System.Diagnostics.Process.ProcessName" } from Node src, Node sink, DataFlowFromMethodToHash conf where conf.hasFlow(src, sink) -select src, "The hash is calculated on the process name $@, may be related to a backdoor. Please review the code for possible malicious intent.", sink, "here" \ No newline at end of file +select src, + "The hash is calculated on the process name $@, may be related to a backdoor. Please review the code for possible malicious intent.", + sink, "here" diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql index e8e2f42dfe4..2e94ea4ad4e 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql @@ -14,19 +14,19 @@ import Solorigate import microsoft.code.csharp.Cryptography.NonCryptographicHashes from Variable v, Literal l, LoopStmt loop, Expr additional_xor -where maybeUsedInFNVFunction( v, _, _, loop) - and ( - exists( BitwiseXorExpr xor2 | - xor2.getAnOperand() = l and additional_xor = xor2 | - loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() - and xor2.getAnOperand() = v.getAnAccess() - ) or exists( AssignXorExpr xor2 | - xor2.getAnOperand() = l and additional_xor = xor2 | - loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() - and xor2.getAnOperand() = v.getAnAccess() - ) - ) - select l, "The variable $@ seems to be used as part of a FNV-like hash calculation, that is modified by an additional $@ expression using literal $@." - , v, v.toString() - , additional_xor, "xor" - , l, l.toString() +where + maybeUsedInFNVFunction(v, _, _, loop) and + ( + exists(BitwiseXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 | + loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() and + xor2.getAnOperand() = v.getAnAccess() + ) + or + exists(AssignXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 | + loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() and + xor2.getAnOperand() = v.getAnAccess() + ) + ) +select l, + "The variable $@ seems to be used as part of a FNV-like hash calculation, that is modified by an additional $@ expression using literal $@.", + v, v.toString(), additional_xor, "xor", l, l.toString() diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql index 154d115a39f..f60d4232004 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql @@ -1,5 +1,5 @@ /** - * @name Number of Solorigate-related command names in enum is above the threshold + * @name Number of Solorigate-related command names in enum is above the threshold * @description The enum contains several values that look similar to command and control command names, which may indicate that the code may have been tampered by an external agent. * It is recommended to review the code and verify that there is no unexpected code in this project. * @kind problem @@ -14,7 +14,9 @@ import csharp import Solorigate from Enum e, int total -where total = countSolorigateCommandInEnum(e) - and total > 10 -select e, "The enum $@ may be related to Solorigate. It matches " + total + " of the values used for commands in the enum." - , e, e.getName() \ No newline at end of file +where + total = countSolorigateCommandInEnum(e) and + total > 10 +select e, + "The enum $@ may be related to Solorigate. It matches " + total + + " of the values used for commands in the enum.", e, e.getName() diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql index 6d4f7818a9e..830a9b48c2a 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql @@ -1,5 +1,5 @@ /** - * @name Number of Solorigate-related Hashes as literals is above the threshold + * @name Number of Solorigate-related Hashes as literals is above the threshold * @description The total number of Solorigate-related hash literals found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. * It is recommended to review the code and verify that there is no unexpected code in this project, however it is highly unlikely the hash values would be present coincideentally * @kind problem @@ -13,11 +13,12 @@ import csharp import Solorigate - from Literal l, int total, int threshold -where total = countSolorigateSuspiciousHash() - and threshold = 5 // out of ~200 known literals - and isSolorigateHash(l) - and total > threshold -select l, "The Hash literal $@ may be related to the Solorigate campaign. Total count = " + total + " is above the threshold " + threshold + "." - , l, l.getValue() \ No newline at end of file +where + total = countSolorigateSuspiciousHash() and + threshold = 5 and // out of ~200 known literals + isSolorigateHash(l) and + total > threshold +select l, + "The Hash literal $@ may be related to the Solorigate campaign. Total count = " + total + + " is above the threshold " + threshold + ".", l, l.getValue() diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql index d736e6fbf42..a280fefddfa 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql @@ -1,5 +1,5 @@ /** - * @name Number of Solorigate-related literals is above the threshold + * @name Number of Solorigate-related literals is above the threshold * @description The total number of Solorigate-related literals found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. * It is recommended to review the code and verify that there is no unexpected code in this project. * @kind problem @@ -13,11 +13,12 @@ import csharp import Solorigate - from Literal l, int total, int threshold -where total = countSolorigateSuspiciousLiterals() - and threshold = 30 // out of ~150 known literals - and isSolorigateLiteral(l) - and total > threshold -select l, "The literal $@ may be related to the Solorigate campaign. Total count = " + total + " is above the threshold " + threshold + "." - , l, l.getValue() \ No newline at end of file +where + total = countSolorigateSuspiciousLiterals() and + threshold = 30 and // out of ~150 known literals + isSolorigateLiteral(l) and + total > threshold +select l, + "The literal $@ may be related to the Solorigate campaign. Total count = " + total + + " is above the threshold " + threshold + ".", l, l.getValue() diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql index f38a2f2dfb8..277d8c745bd 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql @@ -1,5 +1,5 @@ /** - * @name Number of Solorigate-related method names is above the threshold + * @name Number of Solorigate-related method names is above the threshold * @description The total number of Solorigate-related method names found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. * It is recommended to review the code and verify that there is no unexpected code in this project. * @kind problem @@ -13,11 +13,12 @@ import csharp import Solorigate - from Method m, int total, int threshold -where total = countSolorigateSuspiciousMethodNames() - and threshold = 50 // out of ~ 100 known names - and isSolorigateSuspiciousMethodName(m) - and total > threshold -select m, "The method $@ may be related to Solorigate. Total count = " + total + " is above the threshold " + threshold + "." - , m, m.getName() \ No newline at end of file +where + total = countSolorigateSuspiciousMethodNames() and + threshold = 50 and // out of ~ 100 known names + isSolorigateSuspiciousMethodName(m) and + total > threshold +select m, + "The method $@ may be related to Solorigate. Total count = " + total + " is above the threshold " + + threshold + ".", m, m.getName() diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll index 77cd4c0fe2e..15444930fad 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll @@ -1,6 +1,5 @@ -/* * +/* * Provides reusable predicates related to Solorigate - * */ import csharp @@ -8,156 +7,236 @@ import csharp /* * Returns a list of Literals representing process hashes. These are unlikely to be recycled between campaigns, so not expected to have hits, but if present * are almost certainly an indicator of compromise - * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 * and https://github.com/fireeye/sunburst_countermeasures/blob/main/fnv1a_xor_hashes.txt */ + private string solorigateSuspiciousHashes() { - result = [ - "10063651499895178962", "10235971842993272939", "10296494671777307979", "10336842116636872171", "10374841591685794123", "10393903804869831898", "10463926208560207521", - "10484659978517092504", "10501212300031893463", "10545868833523019926", "10657751674541025650", "106672141413120087", "10734127004244879770", "10829648878147112121", - "1099511628211", "11073283311104541690", "1109067043404435916", "11109294216876344399", "11266044540366291518", "11385275378891906608", "11771945869106552231", "11801746708619571308", - "11818825521849580123", "11913842725949116895", "12027963942392743532", "12094027092655598256", "12343334044036541897", "12445177985737237804", "12445232961318634374", - "12574535824074203265", "12679195163651834776", "12709986806548166638", "12718416789200275332", "12785322942775634499", "12790084614253405985", "12969190449276002545", - "13014156621614176974", "13029357933491444455", "13135068273077306806", "13260224381505715848", "13316211011159594063", "13464308873961738403", "13544031715334011032", - "13581776705111912829", "13599785766252827703", "13611051401579634621", "13611814135072561278", "13655261125244647696", "1367627386496056834", "1368907909245890092", "13693525876560827283", - "13783346438774742614", "13799353263187722717", "13825071784440082496", "13852439084267373191", "13876356431472225791", "14055243717250701608", "14079676299181301772", "14095938998438966337", - "14111374107076822891", "14193859431895170587", "14226582801651130532", "14243671177281069512", "14256853800858727521", "14480775929210717493", "14482658293117931546", - "14513577387099045298", "14630721578341374856", "14695981039346656037", "14710585101020280896", "1475579823244607677", "14868920869169964081", "14968320160131875803", "14971809093655817917", - "15039834196857999838", "15092207615430402812", "15114163911481793350", "15194901817027173566", "15267980678929160412", "15457732070353984570", "15514036435533858158", - "15535773470978271326", "15587050164583443069", "155978580751494388", "15695338751700748390", "15997665423159927228", "16066522799090129502", "16066651430762394116", "16112751343173365533", - "16130138450758310172", "1614465773938842903", "16292685861617888592", "16335643316870329598", "16423314183614230717", "16570804352575357627", "1682585410644922036", "16858955978146406642", - "16990567851129491937", "17017923349298346219", "17097380490166623672", "17109238199226571972", "17204844226884380288", "17291806236368054941", "17351543633914244545", - "17439059603042731363", "17574002783607647274", "17624147599670377042", "17633734304611248415", "17683972236092287897", "17849680105131524334", "17939405613729073960", "17956969551821596225", - "17978774977754553159", "17984632978012874803", "17997967489723066537", "18147627057830191163", "18150909006539876521", "18159703063075866524", "18246404330670877335", - "18294908219222222902", "18392881921099771407", "18446744073709551613", "191060519014405309", "2032008861530788751", - "2128122064571842954", "2147483647", "2147745794", "2380224015317016190", "2478231962306073784", "2532538262737333146", - "2589926981877829912", "2597124982561782591", "2600364143812063535", "2717025511528702475", "2734787258623754862", "27407921587843457", "2760663353550280147", - "2797129108883749491", "2810460305047003196", "292198192373389586", "2934149816356927366", "3045986759481489935", "3178468437029279937", "3200333496547938354", "3320026265773918739", - "3320767229281015341", "3341747963119755850", "3407972863931386250", "3413052607651207697", "3413886037471417852", "3421197789791424393", "3421213182954201407", "3425260965299690882", - "3538022140597504361", "3575761800716667678", "3588624367609827560", "3626142665768487764", "3642525650883269872", "3656637464651387014", "3660705254426876796", "3769837838875367802", - "3778500091710709090", "3796405623695665524", "3869935012404164040", "3890769468012566366", "3890794756780010537", "397780960855462669", "4030236413975199654", "4088976323439621041", - "4454255944391929578", "4501656691368064027", "4578480846255629462", "4821863173800309721", "4931721628717906635", "506634811745884560", "5132256620104998637", - "5183687599225757871", "521157249538507889", "5219431737322569038", "541172992193764396", "5415426428750045503", "5449730069165757263", "5587557070429522647", "5614586596107908838", - "576626207276463000", "5942282052525294911", "5945487981219695001", "5984963105389676759", "607197993339007484", - "6088115528707848728", "6116246686670134098", "6180361713414290679", "6195833633417633900", "6274014997237900919", "640589622539783622", "6461429591783621719", "6491986958834001955", - "6508141243778577344", "6605813339339102567", "682250828679635420", "6827032273910657891", "6943102301517884811", "700598796416086955", "7080175711202577138", - "7175363135479931834", "7315838824213522000", "7412338704062093516", "7516148236133302073", "7574774749059321801", "7701683279824397773", "7775177810774851294", "7810436520414958497", - "7878537243757499832", "79089792725215063", "7982848972385914508", "8052533790968282297", "8129411991672431889", "8146185202538899243", "835151375515278827", "8381292265993977266", - "8408095252303317471", "8473756179280619170", "8478833628889826985", "8612208440357175863", "8697424601205169055", "8698326794961817906", "8709004393777297355", "8727477769544302060", - "8760312338504300643", "8799118153397725683", "8873858923435176895", "8994091295115840290", "9007106680104765185", "9061219083560670602", "9149947745824492274", "917638920165491138", "9234894663364701749", - "9333057603143916814", "9384605490088500348", "9531326785919727076", "9555688264681862794", "9559632696372799208", "9903758755917170407" - ] - -} - -/* - * Holds if the literal is one that matches a literal found in Solorigate code. - * - * NOTE: Some of the values have been commented out as they are commonly found elsewhere. - */ -predicate isSolorigateHash(Literal l){ - l.getValue() = solorigateSuspiciousHashes() -} - -/* - * Returns the total number of Solorigate-related literales found in the project - */ -int countSolorigateSuspiciousHash(){ - result = count(string s | exists( Literal l | s = l.getValue() and s = solorigateSuspiciousHashes())) + result = + [ + "10063651499895178962", "10235971842993272939", "10296494671777307979", + "10336842116636872171", "10374841591685794123", "10393903804869831898", + "10463926208560207521", "10484659978517092504", "10501212300031893463", + "10545868833523019926", "10657751674541025650", "106672141413120087", "10734127004244879770", + "10829648878147112121", "1099511628211", "11073283311104541690", "1109067043404435916", + "11109294216876344399", "11266044540366291518", "11385275378891906608", + "11771945869106552231", "11801746708619571308", "11818825521849580123", + "11913842725949116895", "12027963942392743532", "12094027092655598256", + "12343334044036541897", "12445177985737237804", "12445232961318634374", + "12574535824074203265", "12679195163651834776", "12709986806548166638", + "12718416789200275332", "12785322942775634499", "12790084614253405985", + "12969190449276002545", "13014156621614176974", "13029357933491444455", + "13135068273077306806", "13260224381505715848", "13316211011159594063", + "13464308873961738403", "13544031715334011032", "13581776705111912829", + "13599785766252827703", "13611051401579634621", "13611814135072561278", + "13655261125244647696", "1367627386496056834", "1368907909245890092", "13693525876560827283", + "13783346438774742614", "13799353263187722717", "13825071784440082496", + "13852439084267373191", "13876356431472225791", "14055243717250701608", + "14079676299181301772", "14095938998438966337", "14111374107076822891", + "14193859431895170587", "14226582801651130532", "14243671177281069512", + "14256853800858727521", "14480775929210717493", "14482658293117931546", + "14513577387099045298", "14630721578341374856", "14695981039346656037", + "14710585101020280896", "1475579823244607677", "14868920869169964081", "14968320160131875803", + "14971809093655817917", "15039834196857999838", "15092207615430402812", + "15114163911481793350", "15194901817027173566", "15267980678929160412", + "15457732070353984570", "15514036435533858158", "15535773470978271326", + "15587050164583443069", "155978580751494388", "15695338751700748390", "15997665423159927228", + "16066522799090129502", "16066651430762394116", "16112751343173365533", + "16130138450758310172", "1614465773938842903", "16292685861617888592", "16335643316870329598", + "16423314183614230717", "16570804352575357627", "1682585410644922036", "16858955978146406642", + "16990567851129491937", "17017923349298346219", "17097380490166623672", + "17109238199226571972", "17204844226884380288", "17291806236368054941", + "17351543633914244545", "17439059603042731363", "17574002783607647274", + "17624147599670377042", "17633734304611248415", "17683972236092287897", + "17849680105131524334", "17939405613729073960", "17956969551821596225", + "17978774977754553159", "17984632978012874803", "17997967489723066537", + "18147627057830191163", "18150909006539876521", "18159703063075866524", + "18246404330670877335", "18294908219222222902", "18392881921099771407", + "18446744073709551613", "191060519014405309", "2032008861530788751", "2128122064571842954", + "2147483647", "2147745794", "2380224015317016190", "2478231962306073784", + "2532538262737333146", "2589926981877829912", "2597124982561782591", "2600364143812063535", + "2717025511528702475", "2734787258623754862", "27407921587843457", "2760663353550280147", + "2797129108883749491", "2810460305047003196", "292198192373389586", "2934149816356927366", + "3045986759481489935", "3178468437029279937", "3200333496547938354", "3320026265773918739", + "3320767229281015341", "3341747963119755850", "3407972863931386250", "3413052607651207697", + "3413886037471417852", "3421197789791424393", "3421213182954201407", "3425260965299690882", + "3538022140597504361", "3575761800716667678", "3588624367609827560", "3626142665768487764", + "3642525650883269872", "3656637464651387014", "3660705254426876796", "3769837838875367802", + "3778500091710709090", "3796405623695665524", "3869935012404164040", "3890769468012566366", + "3890794756780010537", "397780960855462669", "4030236413975199654", "4088976323439621041", + "4454255944391929578", "4501656691368064027", "4578480846255629462", "4821863173800309721", + "4931721628717906635", "506634811745884560", "5132256620104998637", "5183687599225757871", + "521157249538507889", "5219431737322569038", "541172992193764396", "5415426428750045503", + "5449730069165757263", "5587557070429522647", "5614586596107908838", "576626207276463000", + "5942282052525294911", "5945487981219695001", "5984963105389676759", "607197993339007484", + "6088115528707848728", "6116246686670134098", "6180361713414290679", "6195833633417633900", + "6274014997237900919", "640589622539783622", "6461429591783621719", "6491986958834001955", + "6508141243778577344", "6605813339339102567", "682250828679635420", "6827032273910657891", + "6943102301517884811", "700598796416086955", "7080175711202577138", "7175363135479931834", + "7315838824213522000", "7412338704062093516", "7516148236133302073", "7574774749059321801", + "7701683279824397773", "7775177810774851294", "7810436520414958497", "7878537243757499832", + "79089792725215063", "7982848972385914508", "8052533790968282297", "8129411991672431889", + "8146185202538899243", "835151375515278827", "8381292265993977266", "8408095252303317471", + "8473756179280619170", "8478833628889826985", "8612208440357175863", "8697424601205169055", + "8698326794961817906", "8709004393777297355", "8727477769544302060", "8760312338504300643", + "8799118153397725683", "8873858923435176895", "8994091295115840290", "9007106680104765185", + "9061219083560670602", "9149947745824492274", "917638920165491138", "9234894663364701749", + "9333057603143916814", "9384605490088500348", "9531326785919727076", "9555688264681862794", + "9559632696372799208", "9903758755917170407" + ] } /* - * Returns a list of Literals used by Solorigate - * - * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * Holds if the literal is one that matches a literal found in Solorigate code. + * + * NOTE: Some of the values have been commented out as they are commonly found elsewhere. + */ + +predicate isSolorigateHash(Literal l) { l.getValue() = solorigateSuspiciousHashes() } + +/* + * Returns the total number of Solorigate-related literales found in the project + */ + +int countSolorigateSuspiciousHash() { + result = + count(string s | exists(Literal l | s = l.getValue() and s = solorigateSuspiciousHashes())) +} + +/* + * Returns a list of Literals used by Solorigate + * + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 * and https://github.com/fireeye/sunburst_countermeasures/blob/main/fnv1a_xor_hashes.txt */ + private string solorigateSuspiciousLiterals() { - result = [ "(?i)([^a-z]|^)(test)([^a-z]|$)", "(?i)(solarwinds)", "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n", "[{0,5}] {1}\n", "[E] {0} {1} {2}", - "\"\\{[0-9a-f-]{36}\\}\"|\"[0-9a-f]{32}\"|\"[0-9a-f]{16}\"", ".CortexPlugin", ".Orion", "\"EventName\":\"EventManager\",", "\"EventType\":\"Orion\",", - "\\OrionImprovement\\SolarWinds.OrionImprovement.exe", "0123456789abcdefghijklmnopqrstuvwxyz-_.", - "\"sessionId\":\"{0}\",", "\"steps\":[", "\"Succeeded\":true,", "\"Timestamp\":\"\\/Date({0})\\/\",", "\"userId\":\"{0}\",", "{0} {1} HTTP/{2}\n", - "10140", "144.86.226.0", "154.118.140.0", "172.16.0.0", "18.130.0.0", "184.72.0.0", "192.168.0.0", "199.201.117.0", "20.140.0.0", "20100", "20220", "217.163.7.0", "224.0.0.0", - "240.0.0.0", "255.240.0.0", "255.254.0.0", "255.255.248.0", "3.0.0.382", "41.84.159.0", "43140", "4320", "43260", "524287", "583da945-62af-10e8-4902-a8f205c72b2e", "65280", - "71.152.53.0", "74.114.24.0", "8.18.144.0", "87.238.80.0", "96.31.172.0", "983040", "99.79.0.0", - "Administrator", "advapi32.dll", "Apollo", "appsync-api", "avsvmcloud.com", "api.solarwinds.com", "-root", "-cert", "-universal_ca", "-ca", "-primary_ca", "-timestamp", "-global", "-secureca", "CloudMonitoring", - "MACAddress", "DHCPEnabled", "DHCPServer", "DNSHostName", "DNSDomainSuffixSearchOrder", "DNSServerSearchOrder", "IPAddress", "IPSubnet", "DefaultIPGateway", "OSArchitecture", "InstallDate", "Organization", "RegisteredUser", - "fc00::", "fe00::", "fec0::", "ffc0::", "ff00::", - "HKCC", "HKCR", "HKCU", "HKDD", "HKEY_CLASSES_ROOT", "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA", "HKEY_LOCAL_MACHINE", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography", - "HKEY_PERFOMANCE_DATA", "HKEY_USERS", "HKLM", "HKPD", "HKU", "If-None-Match", "Microsoft-CryptoAPI/", "Nodes", "Volumes", "Interfaces", "Components", - "opensans", "Organization", "OSArchitecture", "ParentProcessID", "PathName", "ReportWatcherPostpone", "ReportWatcherRetry", "S-1-5-", "SeRestorePrivilege", "SeShutdownPrivilege", "SeTakeOwnershipPrivilege", - "SolarWinds", "SolarWindsOrionImprovementClient/", "SourceCodePro", "SourceHanSans", "SourceHanSerif", "SourceSerifPro", "Start", "swip/Events", "swip/upd/", "swip/Upload.ashx", "SYSTEM", - "SYSTEM\\CurrentControlSet\\services", "us-east-1", "us-east-2", "us-west-2", - "fonts/woff/{0}-{1}-{2}{3}.woff2", "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2", "ph2eifo3n5utg1j8d94qrvbmk0sal76c", "pki/crl/{0}{1}{2}.crl", "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj", - "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true", "Select * From Win32_OperatingSystem", "Select * From Win32_Process", "Select * From Win32_SystemDriver", "Select * From Win32_UserAccount"] - -} - -/* - * Holds if the literal is one that matches a literal found in Solorigate code. - * - * NOTE: Some of the values have been commented out as they are commonly found elsewhere. - */ -predicate isSolorigateLiteral(Literal l){ - l.getValue() = solorigateSuspiciousLiterals() -} - -/* - * Returns the total number of Solorigate-related literales found in the project - */ -int countSolorigateSuspiciousLiterals(){ - result = count(string s | exists( Literal l | s = l.getValue() and s = solorigateSuspiciousLiterals())) + result = + [ + "(?i)([^a-z]|^)(test)([^a-z]|$)", "(?i)(solarwinds)", "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n", + "[{0,5}] {1}\n", "[E] {0} {1} {2}", + "\"\\{[0-9a-f-]{36}\\}\"|\"[0-9a-f]{32}\"|\"[0-9a-f]{16}\"", ".CortexPlugin", ".Orion", + "\"EventName\":\"EventManager\",", "\"EventType\":\"Orion\",", + "\\OrionImprovement\\SolarWinds.OrionImprovement.exe", + "0123456789abcdefghijklmnopqrstuvwxyz-_.", "\"sessionId\":\"{0}\",", "\"steps\":[", + "\"Succeeded\":true,", "\"Timestamp\":\"\\/Date({0})\\/\",", "\"userId\":\"{0}\",", + "{0} {1} HTTP/{2}\n", "10140", "144.86.226.0", "154.118.140.0", "172.16.0.0", "18.130.0.0", + "184.72.0.0", "192.168.0.0", "199.201.117.0", "20.140.0.0", "20100", "20220", "217.163.7.0", + "224.0.0.0", "240.0.0.0", "255.240.0.0", "255.254.0.0", "255.255.248.0", "3.0.0.382", + "41.84.159.0", "43140", "4320", "43260", "524287", "583da945-62af-10e8-4902-a8f205c72b2e", + "65280", "71.152.53.0", "74.114.24.0", "8.18.144.0", "87.238.80.0", "96.31.172.0", "983040", + "99.79.0.0", "Administrator", "advapi32.dll", "Apollo", "appsync-api", "avsvmcloud.com", + "api.solarwinds.com", "-root", "-cert", "-universal_ca", "-ca", "-primary_ca", "-timestamp", + "-global", "-secureca", "CloudMonitoring", "MACAddress", "DHCPEnabled", "DHCPServer", + "DNSHostName", "DNSDomainSuffixSearchOrder", "DNSServerSearchOrder", "IPAddress", "IPSubnet", + "DefaultIPGateway", "OSArchitecture", "InstallDate", "Organization", "RegisteredUser", + "fc00::", "fe00::", "fec0::", "ffc0::", "ff00::", "HKCC", "HKCR", "HKCU", "HKDD", + "HKEY_CLASSES_ROOT", "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA", + "HKEY_LOCAL_MACHINE", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography", + "HKEY_PERFOMANCE_DATA", "HKEY_USERS", "HKLM", "HKPD", "HKU", "If-None-Match", + "Microsoft-CryptoAPI/", "Nodes", "Volumes", "Interfaces", "Components", "opensans", + "Organization", "OSArchitecture", "ParentProcessID", "PathName", "ReportWatcherPostpone", + "ReportWatcherRetry", "S-1-5-", "SeRestorePrivilege", "SeShutdownPrivilege", + "SeTakeOwnershipPrivilege", "SolarWinds", "SolarWindsOrionImprovementClient/", + "SourceCodePro", "SourceHanSans", "SourceHanSerif", "SourceSerifPro", "Start", "swip/Events", + "swip/upd/", "swip/Upload.ashx", "SYSTEM", "SYSTEM\\CurrentControlSet\\services", "us-east-1", + "us-east-2", "us-west-2", "fonts/woff/{0}-{1}-{2}{3}.woff2", + "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2", "ph2eifo3n5utg1j8d94qrvbmk0sal76c", + "pki/crl/{0}{1}{2}.crl", "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj", + "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true", + "Select * From Win32_OperatingSystem", "Select * From Win32_Process", + "Select * From Win32_SystemDriver", "Select * From Win32_UserAccount" + ] } /* - * Returns a list of method names used by Solorigate - * - * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * Holds if the literal is one that matches a literal found in Solorigate code. + * + * NOTE: Some of the values have been commented out as they are commonly found elsewhere. */ + +predicate isSolorigateLiteral(Literal l) { l.getValue() = solorigateSuspiciousLiterals() } + +/* + * Returns the total number of Solorigate-related literales found in the project + */ + +int countSolorigateSuspiciousLiterals() { + result = + count(string s | exists(Literal l | s = l.getValue() and s = solorigateSuspiciousLiterals())) +} + +/* + * Returns a list of method names used by Solorigate + * + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + */ + private string solorigateSuspiciousMethodNames() { - result = [ "Abort", "AddFileExecutionEngine", "AddRegistryExecutionEngine", "AdjustTokenPrivileges", "Base64Decode", "Base64Encode", "ByteArrayToHexString", "CheckServerConnection", "Close", "CloseHandle", "CollectSystemDescription", - "Compress", "CreateSecureString", "CreateString", "CreateUploadRequest", "CreateUploadRequestImpl", "Decompress", "DecryptShort", "Deflate", "DelayMin", "DelayMs", "DeleteFile", "DeleteRegistryValue", "DeleteValue", - "ExecuteEngine", "FileExists", "GetAddresses", "GetAddressFamily", "GetArgumentIndex", "GetBaseUri", "GetBaseUriImpl", "GetCache", "GetCurrentProcess", "GetCurrentString", "GetDescriptionId", "GetFileHash", "GetFileSystemEntries", - "GetHash", "GetHive", "GetIntArray", "GetIPHostEntry", "GetManagementObjectProperty", "GetNetworkAdapterConfiguration", "GetNewOwnerName", "GetNextString", "GetNextStringEx", "GetOrCreateUserID", "GetOrionImprovementCustomerId", - "GetOSVersion", "GetPreviousString", "GetProcessByDescription", "GetRegistrySubKeyAndValueNames", "GetStatus", "GetStringHash", "GetSubKeyAndValueNames", "GetUserAgent", "GetValue", "GetWebProxy", "HexStringToByteArray", "Inflate", - "Initialize", "InitiateSystemShutdownExW", "IsNullOrInvalidName", "IsSynchronized", "KillTask", "LookupPrivilegeValueW", "OpenProcessToken", "ParseServiceResponse", "Quote", "ReadConfig", "ReadDeviceInfo", "ReadRegistryValue", - "ReadReportStatus", "ReadServiceStatus", "RebootComputer", "RunTask", "SearchAssemblies", "SearchConfigurations", "SearchServices", "SetAutomaticMode", "SetKeyOwner", "SetKeyOwnerWithPrivileges", "SetKeyPermissions", "SetManualMode", - "SetProcessPrivilege", "SetRegistryValue", "SetTime", "SetValue", "SplitString", "ToString", "TrackEvent", "TrackProcesses", "Unquote", "Unzip", "Update", "UpdateBuffer", "UpdateNotification", "UploadSystemDescription", "Valid", - "WriteConfig", "WriteFile", "WriteReportStatus", "WriteServiceStatus", "Zip"] + result = + [ + "Abort", "AddFileExecutionEngine", "AddRegistryExecutionEngine", "AdjustTokenPrivileges", + "Base64Decode", "Base64Encode", "ByteArrayToHexString", "CheckServerConnection", "Close", + "CloseHandle", "CollectSystemDescription", "Compress", "CreateSecureString", "CreateString", + "CreateUploadRequest", "CreateUploadRequestImpl", "Decompress", "DecryptShort", "Deflate", + "DelayMin", "DelayMs", "DeleteFile", "DeleteRegistryValue", "DeleteValue", "ExecuteEngine", + "FileExists", "GetAddresses", "GetAddressFamily", "GetArgumentIndex", "GetBaseUri", + "GetBaseUriImpl", "GetCache", "GetCurrentProcess", "GetCurrentString", "GetDescriptionId", + "GetFileHash", "GetFileSystemEntries", "GetHash", "GetHive", "GetIntArray", "GetIPHostEntry", + "GetManagementObjectProperty", "GetNetworkAdapterConfiguration", "GetNewOwnerName", + "GetNextString", "GetNextStringEx", "GetOrCreateUserID", "GetOrionImprovementCustomerId", + "GetOSVersion", "GetPreviousString", "GetProcessByDescription", + "GetRegistrySubKeyAndValueNames", "GetStatus", "GetStringHash", "GetSubKeyAndValueNames", + "GetUserAgent", "GetValue", "GetWebProxy", "HexStringToByteArray", "Inflate", "Initialize", + "InitiateSystemShutdownExW", "IsNullOrInvalidName", "IsSynchronized", "KillTask", + "LookupPrivilegeValueW", "OpenProcessToken", "ParseServiceResponse", "Quote", "ReadConfig", + "ReadDeviceInfo", "ReadRegistryValue", "ReadReportStatus", "ReadServiceStatus", + "RebootComputer", "RunTask", "SearchAssemblies", "SearchConfigurations", "SearchServices", + "SetAutomaticMode", "SetKeyOwner", "SetKeyOwnerWithPrivileges", "SetKeyPermissions", + "SetManualMode", "SetProcessPrivilege", "SetRegistryValue", "SetTime", "SetValue", + "SplitString", "ToString", "TrackEvent", "TrackProcesses", "Unquote", "Unzip", "Update", + "UpdateBuffer", "UpdateNotification", "UploadSystemDescription", "Valid", "WriteConfig", + "WriteFile", "WriteReportStatus", "WriteServiceStatus", "Zip" + ] } -/* +/* * Holds if the method is one that matches a method found in Solorigate code. - * - * NOTE: Pretty much all of these method names are common. + * + * NOTE: Pretty much all of these method names are common. */ + predicate isSolorigateSuspiciousMethodName(Method m) { - m.fromSource() and - ( - m.getName() = solorigateSuspiciousMethodNames() - - ) + m.fromSource() and + m.getName() = solorigateSuspiciousMethodNames() } -/* - * Returns the total number of Solorigate-related method names found in the project +/* + * Returns the total number of Solorigate-related method names found in the project */ -int countSolorigateSuspiciousMethodNames(){ - result = count(string s | exists(Method m | s=m.getName() and s = solorigateSuspiciousMethodNames())) + +int countSolorigateSuspiciousMethodNames() { + result = + count(string s | exists(Method m | s = m.getName() and s = solorigateSuspiciousMethodNames())) } - -/* +/* * Returns the total number of Solorigate-related commands in the given enum - * + * * This command list is described at https://www.fireeye.com/blog/products-and-services/2020/12/global-intrusion-campaign-leverages-software-supply-chain-compromise.html - * and the enum names are based from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * and the enum names are based from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 */ + int countSolorigateCommandInEnum(Enum e) { - result = count(string s, EnumConstant ec | - e.getAnEnumConstant() = ec and - s = ec.getName() and - s in [ "Idle", "Exit", "SetTime", "CollectSystemDescription", "UploadSystemDescription", "RunTask", "GetProcessByDescription", "KillTask", - "GetFileSystemEntries", "WriteFile", "FileExists", "DeleteFile", "GetFileHash", "ReadRegistryValue", "SetRegistryValue", - "DeleteRegistryValue", "GetRegistrySubKeyAndValueNames", "Reboot", "None" ] ) + result = + count(string s, EnumConstant ec | + e.getAnEnumConstant() = ec and + s = ec.getName() and + s in [ + "Idle", "Exit", "SetTime", "CollectSystemDescription", "UploadSystemDescription", + "RunTask", "GetProcessByDescription", "KillTask", "GetFileSystemEntries", "WriteFile", + "FileExists", "DeleteFile", "GetFileHash", "ReadRegistryValue", "SetRegistryValue", + "DeleteRegistryValue", "GetRegistrySubKeyAndValueNames", "Reboot", "None" + ] + ) } diff --git a/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll index 4f611bac84b..ea4368af7f6 100644 --- a/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll +++ b/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -1,6 +1,6 @@ -/* * +/* * Predicates that help detect potential non-cryptographic hash functions - * + * * By themselves, non-cryptographic functions are common and not dangerous * These predicates are intended for helping detect non-cryptographic hashes that may be used * in a context that is not appropriate, or for detecting modified hash functions @@ -10,99 +10,98 @@ import csharp private import DataFlow private import semmle.code.csharp.dataflow.TaintTracking2 -predicate maybeANonCryptogrphicHash( Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop ) { - callable = loop.getEnclosingCallable() and - ( - maybeUsedInFNVFunction( v, xor, mul, loop) or - maybeUsedInElfHashFunction( v, xor, mul, loop) - ) +predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Expr mul, LoopStmt loop) { + callable = loop.getEnclosingCallable() and + ( + maybeUsedInFNVFunction(v, xor, mul, loop) or + maybeUsedInElfHashFunction(v, xor, mul, loop) + ) } -/** +/** * Holds if the arguments are used in a way that resembles a FNV hash function * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression * followed by a multiplication `mul` expression. */ -predicate maybeUsedInFNVFunction( Variable v, Expr xor, Expr mul, LoopStmt loop) { - exists( Expr e1, Expr e2 | - exists( Operation axore, Operation amule | - xor = axore and mul = amule | - e1.getAChild*() = v.getAnAccess() and - e2.getAChild*() = v.getAnAccess() and - e1 = axore.getAnOperand() and - e2 = amule.getAnOperand() and - axore.getAControlFlowNode().getASuccessor*() = amule.getAControlFlowNode() and - (axore instanceof AssignXorExpr or axore instanceof BitwiseXorExpr) and - (amule instanceof AssignMulExpr or amule instanceof MulExpr) - ) - ) - and loop.getAChild*() = mul.getEnclosingStmt() - and loop.getAChild*() = xor.getEnclosingStmt() +predicate maybeUsedInFNVFunction(Variable v, Expr xor, Expr mul, LoopStmt loop) { + exists(Expr e1, Expr e2 | + exists(Operation axore, Operation amule | xor = axore and mul = amule | + e1.getAChild*() = v.getAnAccess() and + e2.getAChild*() = v.getAnAccess() and + e1 = axore.getAnOperand() and + e2 = amule.getAnOperand() and + axore.getAControlFlowNode().getASuccessor*() = amule.getAControlFlowNode() and + (axore instanceof AssignXorExpr or axore instanceof BitwiseXorExpr) and + (amule instanceof AssignMulExpr or amule instanceof MulExpr) + ) + ) and + loop.getAChild*() = mul.getEnclosingStmt() and + loop.getAChild*() = xor.getEnclosingStmt() } -/** +/** * Holds if the arguments are used in a way that resembles an Elf-Hash hash function * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression * followed by an addition `add` expression. */ predicate maybeUsedInElfHashFunction(Variable v, Expr xorExpr, Expr addExpr, LoopStmt loop) { - exists( Expr e1, Operation add, Expr e2, AssignExpr addAssign, Operation xor, AssignExpr xorAssign, Operation notOp, AssignExpr notAssign | - xorExpr = xor and - addExpr = add and - ( add instanceof AddExpr or add instanceof AssignAddExpr ) and - e1.getAChild*() = add.getAnOperand() and - e1 instanceof BinaryBitwiseOperation and - e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and - v = addAssign.getTargetVariable() and - addAssign.getAChild*() = add and - ( xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr ) and - addAssign.getAControlFlowNode().getASuccessor*() = xor.getAControlFlowNode() and - xorAssign.getAChild*() = xor and - v = xorAssign.getTargetVariable() and - (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation ) and - xor.getAControlFlowNode().getASuccessor*() = notOp.getAControlFlowNode() and - notAssign.getAChild*() = notOp and - v = notAssign.getTargetVariable() and - loop.getAChild*() = add.getEnclosingStmt() and - loop.getAChild*() = xor.getEnclosingStmt() - ) + exists( + Expr e1, Operation add, Expr e2, AssignExpr addAssign, Operation xor, AssignExpr xorAssign, + Operation notOp, AssignExpr notAssign + | + xorExpr = xor and + addExpr = add and + (add instanceof AddExpr or add instanceof AssignAddExpr) and + e1.getAChild*() = add.getAnOperand() and + e1 instanceof BinaryBitwiseOperation and + e2 = e1.(BinaryBitwiseOperation).getLeftOperand() and + v = addAssign.getTargetVariable() and + addAssign.getAChild*() = add and + (xor instanceof BitwiseXorExpr or xor instanceof AssignXorExpr) and + addAssign.getAControlFlowNode().getASuccessor*() = xor.getAControlFlowNode() and + xorAssign.getAChild*() = xor and + v = xorAssign.getTargetVariable() and + (notOp instanceof UnaryBitwiseOperation or notOp instanceof AssignBitwiseOperation) and + xor.getAControlFlowNode().getASuccessor*() = notOp.getAControlFlowNode() and + notAssign.getAChild*() = notOp and + v = notAssign.getTargetVariable() and + loop.getAChild*() = add.getEnclosingStmt() and + loop.getAChild*() = xor.getEnclosingStmt() + ) } /** * Any dataflow from any source to any sink, used internally */ private class AnyDataFlow extends TaintTracking2::Configuration { - AnyDataFlow() { - this = "DataFlowFromDataGatheringMethodToVariable" - } + AnyDataFlow() { this = "DataFlowFromDataGatheringMethodToVariable" } - override predicate isSource(Node source) { - any() - } + override predicate isSource(Node source) { any() } - override predicate isSink(Node sink) - { - any() - } + override predicate isSink(Node sink) { any() } } -/** +/** * Holds if the Callable is a function that behaves like a non-cryptographic hash * where the parameter `param` is likely the message to hash */ -predicate isCallableAPotentialNonCryptographicHashFunction( Callable callable, Parameter param) { - exists( Variable v, Expr op1, Expr op2, LoopStmt loop | - maybeANonCryptogrphicHash(callable, v, op1, op2, loop) - and callable.getAParameter() = param - and ( - param.getAnAccess() = op1.(Operation).getAnOperand().getAChild*() or - param.getAnAccess() = op2.(Operation).getAnOperand().getAChild*() or - exists( AnyDataFlow config, Node source, Node sink | - ( sink.asExpr() = op1.(Operation).getAChild*() or - sink.asExpr() = op2.(Operation).getAChild*()) and - source.asExpr() = param.getAnAccess() and - config.hasFlow(source, sink) - ) - ) - ) +predicate isCallableAPotentialNonCryptographicHashFunction(Callable callable, Parameter param) { + exists(Variable v, Expr op1, Expr op2, LoopStmt loop | + maybeANonCryptogrphicHash(callable, v, op1, op2, loop) and + callable.getAParameter() = param and + ( + param.getAnAccess() = op1.(Operation).getAnOperand().getAChild*() + or + param.getAnAccess() = op2.(Operation).getAnOperand().getAChild*() + or + exists(AnyDataFlow config, Node source, Node sink | + ( + sink.asExpr() = op1.(Operation).getAChild*() or + sink.asExpr() = op2.(Operation).getAChild*() + ) and + source.asExpr() = param.getAnAccess() and + config.hasFlow(source, sink) + ) + ) + ) } From 3be229f097d1d41bf4154a09ecaecc48da4b80f7 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 11:09:30 +0100 Subject: [PATCH 105/429] C#: Separate visitors to dedicated files, rename and reorganize comment extraction related classes --- .../Semmle.Extraction.CSharp/Analyser.cs | 4 +- .../Entities/CommentLine.cs | 93 +------------ .../Populators/Comments.cs | 33 ----- .../Populators/CompilationUnitVisitor.cs | 51 +++++++ .../Populators/TriviaPopulator.cs | 127 ++++++++++++++++++ ...ilationUnit.cs => TypeContainerVisitor.cs} | 68 ---------- .../Populators/TypeOrNamespaceVisitor.cs | 24 ++++ 7 files changed, 205 insertions(+), 195 deletions(-) delete mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs rename csharp/extractor/Semmle.Extraction.CSharp/Populators/{CompilationUnit.cs => TypeContainerVisitor.cs} (56%) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 1222403515f..b4076956c4f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -374,9 +374,9 @@ namespace Semmle.Extraction.CSharp if (!upToDate) { var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); - Populators.CompilationUnit.Extract(cx, tree.GetRoot()); + CompilationUnitVisitor.Extract(cx, tree.GetRoot()); cx.PopulateAll(); - cx.ExtractComments(cx.CommentGenerator); + TriviaPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator); cx.PopulateAll(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs index ba1770f20e5..f6348211695 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs @@ -21,97 +21,6 @@ namespace Semmle.Extraction.CSharp.Entities public string Text { get { return symbol.Item2; } } public string RawText { get; private set; } - public static void Extract(Context cx, SyntaxTrivia trivia) - { - switch (trivia.Kind()) - { - case SyntaxKind.SingleLineDocumentationCommentTrivia: - /* - This is actually a multi-line comment consisting of /// lines. - So split it up. - */ - - var text = trivia.ToFullString(); - - var split = text.Split('\n'); - var currentLocation = trivia.GetLocation().SourceSpan.Start - 3; - - for (var line = 0; line < split.Length - 1; ++line) - { - var fullLine = split[line]; - var nextLineLocation = currentLocation + fullLine.Length + 1; - fullLine = fullLine.TrimEnd('\r'); - var trimmedLine = fullLine; - - var leadingSpaces = trimmedLine.IndexOf('/'); - if (leadingSpaces != -1) - { - fullLine = fullLine.Substring(leadingSpaces); - currentLocation += leadingSpaces; - trimmedLine = trimmedLine.Substring(leadingSpaces + 3); // Remove leading spaces and the "///" - trimmedLine = trimmedLine.Trim(); - - var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); - var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); - var commentType = CommentLineType.XmlDoc; - cx.CommentGenerator.AddComment(Create(cx, location, commentType, trimmedLine, fullLine)); - } - else - { - cx.ModelError("Unexpected comment format"); - } - currentLocation = nextLineLocation; - } - break; - - case SyntaxKind.SingleLineCommentTrivia: - { - var contents = trivia.ToString().Substring(2); - var commentType = CommentLineType.Singleline; - if (contents.Length > 0 && contents[0] == '/') - { - commentType = CommentLineType.XmlDoc; - contents = contents.Substring(1); // An XML comment. - } - cx.CommentGenerator.AddComment(Create(cx, trivia.GetLocation(), commentType, contents.Trim(), trivia.ToFullString())); - } - break; - case SyntaxKind.MultiLineDocumentationCommentTrivia: - case SyntaxKind.MultiLineCommentTrivia: - /* We receive a single SyntaxTrivia for a multiline block spanning several lines. - So we split it into separate lines - */ - text = trivia.ToFullString(); - - split = text.Split('\n'); - currentLocation = trivia.GetLocation().SourceSpan.Start; - - for (var line = 0; line < split.Length; ++line) - { - var fullLine = split[line]; - var nextLineLocation = currentLocation + fullLine.Length + 1; - fullLine = fullLine.TrimEnd('\r'); - var trimmedLine = fullLine; - if (line == 0) - trimmedLine = trimmedLine.Substring(2); - if (line == split.Length - 1) - trimmedLine = trimmedLine.Substring(0, trimmedLine.Length - 2); - trimmedLine = trimmedLine.Trim(); - - var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); - var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); - var commentType = line == 0 ? CommentLineType.Multiline : CommentLineType.MultilineContinuation; - cx.CommentGenerator.AddComment(Create(cx, location, commentType, trimmedLine, fullLine)); - currentLocation = nextLineLocation; - } - break; - // Strangely, these are reported as SingleLineCommentTrivia. - case SyntaxKind.DocumentationCommentExteriorTrivia: - cx.ModelError($"Unhandled comment type {trivia.Kind()} for {trivia}"); - break; - } - } - private Extraction.Entities.Location location; public override void Populate(TextWriter trapFile) @@ -131,7 +40,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.Write(";commentline"); } - private static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) + internal static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) { var init = (loc, type, text, raw); return CommentLineFactory.Instance.CreateEntity(cx, init, init); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs deleted file mode 100644 index 8f6bb6f5206..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Comments.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Semmle.Extraction.CommentProcessing; -using System; - -namespace Semmle.Extraction.CSharp.Populators -{ - /// - /// Populators for comments. - /// - public static class Comments - { - public static void ExtractComments(this Context cx, ICommentGenerator gen) - { - cx.Try(null, null, () => - { - gen.GenerateBindings((entity, duplicationGuardKey, block, binding) => - { - var commentBlock = Entities.CommentBlock.Create(cx, block); - Action a = () => - { - commentBlock.BindTo(entity, binding); - }; - // When the duplication guard key exists, it means that the entity is guarded against - // trap duplication (). - // We must therefore also guard comment construction. - if (duplicationGuardKey != null) - cx.WithDuplicationGuard(duplicationGuardKey, a); - else - a(); - }); - }); - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs new file mode 100644 index 00000000000..a98816fc23e --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -0,0 +1,51 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Util.Logging; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class CompilationUnitVisitor : TypeOrNamespaceVisitor + { + private CompilationUnitVisitor(Context cx) + : base(cx, cx.TrapWriter.Writer, null) { } + + public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) + { + // This information is not yet extracted. + cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Extraction.Entities.Location.Create(cx, node.GetLocation()), "", Severity.Info); + } + + public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) + { + foreach (var m in compilationUnit.ChildNodes()) + { + cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); + } + + // Gather comments: + foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span)) + { + TriviaPopulator.ExtractTrivia(cx, trivia); + } + + foreach (var trivia in compilationUnit.GetLeadingTrivia()) + { + TriviaPopulator.ExtractTrivia(cx, trivia); + } + + foreach (var trivia in compilationUnit.GetTrailingTrivia()) + { + TriviaPopulator.ExtractTrivia(cx, trivia); + } + } + + public static void Extract(Context cx, SyntaxNode unit) + { + // Ensure that the file itself is populated in case the source file is totally empty + Extraction.Entities.File.Create(cx, unit.SyntaxTree.FilePath); + + ((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx)); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs new file mode 100644 index 00000000000..8aa99960a5b --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs @@ -0,0 +1,127 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Semmle.Extraction.CommentProcessing; +using Semmle.Extraction.CSharp.Entities; +using System; + +namespace Semmle.Extraction.CSharp.Populators +{ + /// + /// Populators for trivias. + /// + public static class TriviaPopulator + { + public static void ExtractCommentBlocks(Context cx, ICommentGenerator gen) + { + cx.Try(null, null, () => + { + gen.GenerateBindings((entity, duplicationGuardKey, block, binding) => + { + var commentBlock = Entities.CommentBlock.Create(cx, block); + Action a = () => + { + commentBlock.BindTo(entity, binding); + }; + // When the duplication guard key exists, it means that the entity is guarded against + // trap duplication (). + // We must therefore also guard comment construction. + if (duplicationGuardKey != null) + cx.WithDuplicationGuard(duplicationGuardKey, a); + else + a(); + }); + }); + } + + public static void ExtractTrivia(Context cx, SyntaxTrivia trivia) + { + switch (trivia.Kind()) + { + case SyntaxKind.SingleLineDocumentationCommentTrivia: + /* + This is actually a multi-line comment consisting of /// lines. + So split it up. + */ + + var text = trivia.ToFullString(); + + var split = text.Split('\n'); + var currentLocation = trivia.GetLocation().SourceSpan.Start - 3; + + for (var line = 0; line < split.Length - 1; ++line) + { + var fullLine = split[line]; + var nextLineLocation = currentLocation + fullLine.Length + 1; + fullLine = fullLine.TrimEnd('\r'); + var trimmedLine = fullLine; + + var leadingSpaces = trimmedLine.IndexOf('/'); + if (leadingSpaces != -1) + { + fullLine = fullLine.Substring(leadingSpaces); + currentLocation += leadingSpaces; + trimmedLine = trimmedLine.Substring(leadingSpaces + 3); // Remove leading spaces and the "///" + trimmedLine = trimmedLine.Trim(); + + var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); + var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); + var commentType = CommentLineType.XmlDoc; + cx.CommentGenerator.AddComment(CommentLine.Create(cx, location, commentType, trimmedLine, fullLine)); + } + else + { + cx.ModelError("Unexpected comment format"); + } + currentLocation = nextLineLocation; + } + break; + + case SyntaxKind.SingleLineCommentTrivia: + { + var contents = trivia.ToString().Substring(2); + var commentType = CommentLineType.Singleline; + if (contents.Length > 0 && contents[0] == '/') + { + commentType = CommentLineType.XmlDoc; + contents = contents.Substring(1); // An XML comment. + } + cx.CommentGenerator.AddComment(CommentLine.Create(cx, trivia.GetLocation(), commentType, contents.Trim(), trivia.ToFullString())); + } + break; + case SyntaxKind.MultiLineDocumentationCommentTrivia: + case SyntaxKind.MultiLineCommentTrivia: + /* We receive a single SyntaxTrivia for a multiline block spanning several lines. + So we split it into separate lines + */ + text = trivia.ToFullString(); + + split = text.Split('\n'); + currentLocation = trivia.GetLocation().SourceSpan.Start; + + for (var line = 0; line < split.Length; ++line) + { + var fullLine = split[line]; + var nextLineLocation = currentLocation + fullLine.Length + 1; + fullLine = fullLine.TrimEnd('\r'); + var trimmedLine = fullLine; + if (line == 0) + trimmedLine = trimmedLine.Substring(2); + if (line == split.Length - 1) + trimmedLine = trimmedLine.Substring(0, trimmedLine.Length - 2); + trimmedLine = trimmedLine.Trim(); + + var span = Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(currentLocation, currentLocation + fullLine.Length); + var location = Microsoft.CodeAnalysis.Location.Create(trivia.SyntaxTree, span); + var commentType = line == 0 ? CommentLineType.Multiline : CommentLineType.MultilineContinuation; + cx.CommentGenerator.AddComment(CommentLine.Create(cx, location, commentType, trimmedLine, fullLine)); + currentLocation = nextLineLocation; + } + break; + // Strangely, these are reported as SingleLineCommentTrivia. + case SyntaxKind.DocumentationCommentExteriorTrivia: + cx.ModelError($"Unhandled comment type {trivia.Kind()} for {trivia}"); + break; + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs similarity index 56% rename from csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs index 69814bf197a..a45ede39501 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnit.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs @@ -1,10 +1,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Entities; using Semmle.Extraction.Entities; -using Semmle.Util; -using Semmle.Util.Logging; using System; using System.Collections.Generic; using System.IO; @@ -82,69 +79,4 @@ namespace Semmle.Extraction.CSharp.Populators } } } - - internal class TypeOrNamespaceVisitor : TypeContainerVisitor - { - public TypeOrNamespaceVisitor(Context cx, TextWriter trapFile, IEntity parent) - : base(cx, trapFile, parent) { } - - public override void VisitUsingDirective(UsingDirectiveSyntax usingDirective) - { - // Only deal with "using namespace" not "using X = Y" - if (usingDirective.Alias == null) - new UsingDirective(cx, usingDirective, (NamespaceDeclaration)parent); - } - - public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) - { - NamespaceDeclaration.Create(cx, node, (NamespaceDeclaration)parent); - } - } - - internal class CompilationUnitVisitor : TypeOrNamespaceVisitor - { - public CompilationUnitVisitor(Context cx) - : base(cx, cx.TrapWriter.Writer, null) { } - - public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) - { - // This information is not yet extracted. - cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Extraction.Entities.Location.Create(cx, node.GetLocation()), "", Severity.Info); - } - - public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) - { - foreach (var m in compilationUnit.ChildNodes()) - { - cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); - } - - // Gather comments: - foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span)) - { - CommentLine.Extract(cx, trivia); - } - - foreach (var trivia in compilationUnit.GetLeadingTrivia()) - { - CommentLine.Extract(cx, trivia); - } - - foreach (var trivia in compilationUnit.GetTrailingTrivia()) - { - CommentLine.Extract(cx, trivia); - } - } - } - - public class CompilationUnit - { - public static void Extract(Context cx, SyntaxNode unit) - { - // Ensure that the file itself is populated in case the source file is totally empty - Semmle.Extraction.Entities.File.Create(cx, unit.SyntaxTree.FilePath); - - ((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx)); - } - } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs new file mode 100644 index 00000000000..aacdc5d2a4f --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs @@ -0,0 +1,24 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.CSharp.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class TypeOrNamespaceVisitor : TypeContainerVisitor + { + public TypeOrNamespaceVisitor(Context cx, TextWriter trapFile, IEntity parent) + : base(cx, trapFile, parent) { } + + public override void VisitUsingDirective(UsingDirectiveSyntax usingDirective) + { + // Only deal with "using namespace" not "using X = Y" + if (usingDirective.Alias == null) + new UsingDirective(cx, usingDirective, (NamespaceDeclaration)parent); + } + + public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) + { + NamespaceDeclaration.Create(cx, node, (NamespaceDeclaration)parent); + } + } +} From c3ef6841d093356a78c715c75d753f7496d376e3 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 11:13:21 +0100 Subject: [PATCH 106/429] Add tests for trivia types --- .../comments/BindingAfter.expected | 1 + .../library-tests/comments/Comments.expected | 3 + .../library-tests/comments/Orphans.expected | 1 + .../ql/test/library-tests/comments/trivia.cs | 78 +++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 csharp/ql/test/library-tests/comments/trivia.cs diff --git a/csharp/ql/test/library-tests/comments/BindingAfter.expected b/csharp/ql/test/library-tests/comments/BindingAfter.expected index 44c01d79239..6838f406708 100644 --- a/csharp/ql/test/library-tests/comments/BindingAfter.expected +++ b/csharp/ql/test/library-tests/comments/BindingAfter.expected @@ -55,3 +55,4 @@ | comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | GenericClass<> | | comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:128:9:128:17 | return ...; | x | +| trivia.cs:1:1:3:15 | // ... | trivia.cs:14:7:14:9 | Tr1 | semmle-extractor-options: --standalone | diff --git a/csharp/ql/test/library-tests/comments/Comments.expected b/csharp/ql/test/library-tests/comments/Comments.expected index 388687e7857..80208664157 100644 --- a/csharp/ql/test/library-tests/comments/Comments.expected +++ b/csharp/ql/test/library-tests/comments/Comments.expected @@ -70,6 +70,9 @@ singlelineComment | comments2.cs:124:5:124:16 | // ... | comments2.cs:124:5:124:16 | // ... | 1 | GenericFn | // GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:127:20:127:23 | // ... | 1 | x | // x | | comments2.cs:132:1:132:21 | // ... | comments2.cs:132:1:132:21 | // ... | 1 | End of comment2.cs | // End of comment2.cs | +| trivia.cs:1:1:3:15 | // ... | trivia.cs:1:1:1:42 | // ... | 3 | semmle-extractor-options: --standalone | // semmle-extractor-options: --standalone | +| trivia.cs:1:1:3:15 | // ... | trivia.cs:2:1:2:21 | // ... | 3 | Start of trivia.cs | // Start of trivia.cs | +| trivia.cs:1:1:3:15 | // ... | trivia.cs:3:1:3:15 | // ... | 3 | Unassociated | // Unassociated | multilineComment | comments1.cs:11:1:11:25 | /* ... */ | comments1.cs:11:1:11:25 | /* ... */ | 1 | A multiline comment | /* A multiline comment */ | | comments1.cs:25:1:25:43 | /* ... */ | comments1.cs:25:1:25:15 | /* ... */ | 2 | This is a | /* This is a */ | diff --git a/csharp/ql/test/library-tests/comments/Orphans.expected b/csharp/ql/test/library-tests/comments/Orphans.expected index e57bc81990e..56e5af20cd2 100644 --- a/csharp/ql/test/library-tests/comments/Orphans.expected +++ b/csharp/ql/test/library-tests/comments/Orphans.expected @@ -14,3 +14,4 @@ | comments2.cs:5:27:5:41 | // ... | | comments2.cs:8:1:8:15 | // ... | | comments2.cs:132:1:132:21 | // ... | +| trivia.cs:1:1:3:15 | // ... | diff --git a/csharp/ql/test/library-tests/comments/trivia.cs b/csharp/ql/test/library-tests/comments/trivia.cs new file mode 100644 index 00000000000..e22ddf77a63 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/trivia.cs @@ -0,0 +1,78 @@ +// semmle-extractor-options: --standalone +// Start of trivia.cs +// Unassociated +#define DEBUG + +#undef DEBUG + +using System; +using System.Collections; +using System.Collections.Generic; + +#pragma warning disable 414, CS3021 +#pragma checksum "file.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "ab007f1d23d9" // New checksum +class Tr1 +{ + static void M1() + { +#line 200 "Special" + int i; + int j; +#line default + char c; +#pragma warning restore + float f; +#line hidden // numbering not affected + string s; +#line default + double d; + } +} + +class Tr2 +{ + static void M1() + { + #region fields + int i; + #region nested + int j; + #endregion + #endregion + } +} + +class Tr3 +{ + static void M1() + { +#nullable disable// Sets the nullable annotation and warning contexts to disabled. +#nullable enable// Sets the nullable annotation and warning contexts to enabled. +#nullable restore// Restores the nullable annotation and warning contexts to project settings. +#nullable disable annotations// Sets the nullable annotation context to disabled. +#nullable enable annotations// Sets the nullable annotation context to enabled. +#nullable restore annotations// Restores the nullable annotation context to project settings. +#nullable disable warnings// Sets the nullable warning context to disabled. +#nullable enable warnings// Sets the nullable warning context to enabled. +#nullable restore warnings// Restores the nullable warning context to project settings. + } +} + +class Tr4 +{ + static void M1() + { +#if DEBUG +#warning DEBUG is defined + var i = 0; +#if NESTED + i--; +#endif +#elif (NOTDEBUG == true) || !(TEST) +#error NOTDEBUG is defined or TEST is not + var i = 1; +#else + var i = 2; +#endif + } +} \ No newline at end of file From 046a37b8342fe45dd9376358a8ba89ce60fcb503 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 12:23:06 +0100 Subject: [PATCH 107/429] Simplify element access extraction --- .../Entities/Expressions/ElementAccess.cs | 8 +-- .../Populators/Ast.cs | 63 ------------------- .../arguments/argumentType.expected | 12 ++++ 3 files changed, 14 insertions(+), 69 deletions(-) delete mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index afc4cd2cd93..59e573984fe 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -30,12 +30,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } else { - var child = -1; - Create(cx, qualifier, this, child++); - foreach (var a in argumentList.Arguments) - { - cx.Extract(a, this, child++); - } + Create(cx, qualifier, this, -1); + PopulateArguments(trapFile, argumentList, 0); var symbolInfo = cx.GetSymbolInfo(base.Syntax); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs deleted file mode 100644 index 866d436bda1..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Ast.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Entities; - -namespace Semmle.Extraction.CSharp.Populators -{ - internal class Ast : CSharpSyntaxVisitor - { - private readonly Context cx; - private readonly IExpressionParentEntity parent; - private readonly int child; - - public Ast(Context cx, IExpressionParentEntity parent, int child) - { - this.cx = cx; - this.parent = parent; - this.child = child; - } - - public override void DefaultVisit(SyntaxNode node) - { - cx.ModelError(node, $"Unhandled syntax node {node.Kind()}"); - } - - public override void VisitArgumentList(ArgumentListSyntax node) - { - var c = 0; - foreach (var m in node.Arguments) - { - cx.Extract(m, parent, c++); - } - } - - public override void VisitArgument(ArgumentSyntax node) - { - Expression.Create(cx, node.Expression, parent, child); - } - } - - public static class AstExtensions - { - public static void Extract(this Context cx, CSharpSyntaxNode node, IExpressionParentEntity parent, int child) - { - using (cx.StackGuard) - { - try - { - node.Accept(new Ast(cx, parent, child)); - } - catch (System.Exception ex) // lgtm[cs/catch-of-all-exceptions] - { - cx.ModelError(node, $"Exception processing syntax node of type {node.Kind()}: {ex.Message}"); - } - } - } - - public static void Extract(this Context cx, SyntaxNode node, IEntity parent, int child) - { - cx.Extract(((CSharpSyntaxNode)node), parent, child); - } - } -} diff --git a/csharp/ql/test/library-tests/arguments/argumentType.expected b/csharp/ql/test/library-tests/arguments/argumentType.expected index 39697e63729..e2cd7fc4a51 100644 --- a/csharp/ql/test/library-tests/arguments/argumentType.expected +++ b/csharp/ql/test/library-tests/arguments/argumentType.expected @@ -22,3 +22,15 @@ | arguments.cs:40:41:40:41 | 0 | 0 | | arguments.cs:45:12:45:32 | array creation of type Object[] | 0 | | arguments.cs:45:35:45:38 | null | 0 | +| arguments.cs:55:21:55:21 | 1 | 0 | +| arguments.cs:55:24:55:24 | 2 | 0 | +| arguments.cs:56:21:56:21 | 3 | 0 | +| arguments.cs:56:24:56:24 | 4 | 0 | +| arguments.cs:59:14:59:14 | 8 | 0 | +| arguments.cs:59:17:59:17 | 9 | 0 | +| arguments.cs:60:14:60:15 | 10 | 0 | +| arguments.cs:60:14:60:15 | 10 | 0 | +| arguments.cs:60:18:60:19 | 11 | 0 | +| arguments.cs:60:18:60:19 | 11 | 0 | +| arguments.cs:62:21:62:22 | 15 | 0 | +| arguments.cs:62:25:62:26 | 16 | 0 | From 48d24b2264ab65d5877174251b3430d85ff5162d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 13:40:33 +0100 Subject: [PATCH 108/429] Get line comments from trivia lines --- .../Populators/CompilationUnitVisitor.cs | 2 +- .../test/library-tests/comments/BindingAfter.expected | 2 ++ .../library-tests/comments/BindingBefore.expected | 1 + .../library-tests/comments/BindingParent.expected | 10 ++++++++++ .../ql/test/library-tests/comments/Bindings.expected | 11 +++++++++++ .../ql/test/library-tests/comments/Comments.expected | 11 +++++++++++ 6 files changed, 36 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs index a98816fc23e..918366de186 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Populators } // Gather comments: - foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span)) + foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true)) { TriviaPopulator.ExtractTrivia(cx, trivia); } diff --git a/csharp/ql/test/library-tests/comments/BindingAfter.expected b/csharp/ql/test/library-tests/comments/BindingAfter.expected index 6838f406708..a44d0360f73 100644 --- a/csharp/ql/test/library-tests/comments/BindingAfter.expected +++ b/csharp/ql/test/library-tests/comments/BindingAfter.expected @@ -56,3 +56,5 @@ | comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:128:9:128:17 | return ...; | x | | trivia.cs:1:1:3:15 | // ... | trivia.cs:14:7:14:9 | Tr1 | semmle-extractor-options: --standalone | +| trivia.cs:13:84:13:98 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | +| trivia.cs:25:14:25:38 | // ... | trivia.cs:26:9:26:17 | ... ...; | numbering not affected | diff --git a/csharp/ql/test/library-tests/comments/BindingBefore.expected b/csharp/ql/test/library-tests/comments/BindingBefore.expected index 4d41ea94864..9cb36b9e7cc 100644 --- a/csharp/ql/test/library-tests/comments/BindingBefore.expected +++ b/csharp/ql/test/library-tests/comments/BindingBefore.expected @@ -48,3 +48,4 @@ | comments2.cs:124:5:124:16 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:127:9:127:18 | ... ...; | x | | comments2.cs:132:1:132:21 | // ... | comments2.cs:11:7:11:8 | C2 | End of comment2.cs | +| trivia.cs:25:14:25:38 | // ... | trivia.cs:24:9:24:16 | ... ...; | numbering not affected | diff --git a/csharp/ql/test/library-tests/comments/BindingParent.expected b/csharp/ql/test/library-tests/comments/BindingParent.expected index de8fed3666b..d9c8f24d48d 100644 --- a/csharp/ql/test/library-tests/comments/BindingParent.expected +++ b/csharp/ql/test/library-tests/comments/BindingParent.expected @@ -47,3 +47,13 @@ | comments2.cs:121:17:121:20 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | f | | comments2.cs:124:5:124:16 | // ... | comments2.cs:11:7:11:8 | C2 | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:126:5:129:5 | {...} | x | +| trivia.cs:25:14:25:38 | // ... | trivia.cs:17:5:29:5 | {...} | numbering not affected | +| trivia.cs:49:18:49:82 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation and warning contexts to disabled. | +| trivia.cs:50:17:50:80 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation and warning contexts to enabled. | +| trivia.cs:51:18:51:94 | // ... | trivia.cs:48:5:58:5 | {...} | Restores the nullable annotation and warning contexts to project settings. | +| trivia.cs:52:30:52:81 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation context to disabled. | +| trivia.cs:53:29:53:79 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation context to enabled. | +| trivia.cs:54:30:54:93 | // ... | trivia.cs:48:5:58:5 | {...} | Restores the nullable annotation context to project settings. | +| trivia.cs:55:27:55:75 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable warning context to disabled. | +| trivia.cs:56:26:56:73 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable warning context to enabled. | +| trivia.cs:57:27:57:87 | // ... | trivia.cs:48:5:58:5 | {...} | Restores the nullable warning context to project settings. | diff --git a/csharp/ql/test/library-tests/comments/Bindings.expected b/csharp/ql/test/library-tests/comments/Bindings.expected index b241ed56b55..90889ddeda0 100644 --- a/csharp/ql/test/library-tests/comments/Bindings.expected +++ b/csharp/ql/test/library-tests/comments/Bindings.expected @@ -49,3 +49,14 @@ | comments2.cs:121:17:121:20 | // ... | comments2.cs:121:13:121:13 | f | f | | comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:127:9:127:18 | ... ...; | x | +| trivia.cs:13:84:13:98 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | +| trivia.cs:25:14:25:38 | // ... | trivia.cs:17:5:29:5 | {...} | numbering not affected | +| trivia.cs:49:18:49:82 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation and warning contexts to disabled. | +| trivia.cs:50:17:50:80 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation and warning contexts to enabled. | +| trivia.cs:51:18:51:94 | // ... | trivia.cs:48:5:58:5 | {...} | Restores the nullable annotation and warning contexts to project settings. | +| trivia.cs:52:30:52:81 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation context to disabled. | +| trivia.cs:53:29:53:79 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation context to enabled. | +| trivia.cs:54:30:54:93 | // ... | trivia.cs:48:5:58:5 | {...} | Restores the nullable annotation context to project settings. | +| trivia.cs:55:27:55:75 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable warning context to disabled. | +| trivia.cs:56:26:56:73 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable warning context to enabled. | +| trivia.cs:57:27:57:87 | // ... | trivia.cs:48:5:58:5 | {...} | Restores the nullable warning context to project settings. | diff --git a/csharp/ql/test/library-tests/comments/Comments.expected b/csharp/ql/test/library-tests/comments/Comments.expected index 80208664157..176211192a6 100644 --- a/csharp/ql/test/library-tests/comments/Comments.expected +++ b/csharp/ql/test/library-tests/comments/Comments.expected @@ -73,6 +73,17 @@ singlelineComment | trivia.cs:1:1:3:15 | // ... | trivia.cs:1:1:1:42 | // ... | 3 | semmle-extractor-options: --standalone | // semmle-extractor-options: --standalone | | trivia.cs:1:1:3:15 | // ... | trivia.cs:2:1:2:21 | // ... | 3 | Start of trivia.cs | // Start of trivia.cs | | trivia.cs:1:1:3:15 | // ... | trivia.cs:3:1:3:15 | // ... | 3 | Unassociated | // Unassociated | +| trivia.cs:13:84:13:98 | // ... | trivia.cs:13:84:13:98 | // ... | 1 | New checksum | // New checksum | +| trivia.cs:25:14:25:38 | // ... | trivia.cs:25:14:25:38 | // ... | 1 | numbering not affected | // numbering not affected | +| trivia.cs:49:18:49:82 | // ... | trivia.cs:49:18:49:82 | // ... | 1 | Sets the nullable annotation and warning contexts to disabled. | // Sets the nullable annotation and warning contexts to disabled. | +| trivia.cs:50:17:50:80 | // ... | trivia.cs:50:17:50:80 | // ... | 1 | Sets the nullable annotation and warning contexts to enabled. | // Sets the nullable annotation and warning contexts to enabled. | +| trivia.cs:51:18:51:94 | // ... | trivia.cs:51:18:51:94 | // ... | 1 | Restores the nullable annotation and warning contexts to project settings. | // Restores the nullable annotation and warning contexts to project settings. | +| trivia.cs:52:30:52:81 | // ... | trivia.cs:52:30:52:81 | // ... | 1 | Sets the nullable annotation context to disabled. | // Sets the nullable annotation context to disabled. | +| trivia.cs:53:29:53:79 | // ... | trivia.cs:53:29:53:79 | // ... | 1 | Sets the nullable annotation context to enabled. | // Sets the nullable annotation context to enabled. | +| trivia.cs:54:30:54:93 | // ... | trivia.cs:54:30:54:93 | // ... | 1 | Restores the nullable annotation context to project settings. | // Restores the nullable annotation context to project settings. | +| trivia.cs:55:27:55:75 | // ... | trivia.cs:55:27:55:75 | // ... | 1 | Sets the nullable warning context to disabled. | // Sets the nullable warning context to disabled. | +| trivia.cs:56:26:56:73 | // ... | trivia.cs:56:26:56:73 | // ... | 1 | Sets the nullable warning context to enabled. | // Sets the nullable warning context to enabled. | +| trivia.cs:57:27:57:87 | // ... | trivia.cs:57:27:57:87 | // ... | 1 | Restores the nullable warning context to project settings. | // Restores the nullable warning context to project settings. | multilineComment | comments1.cs:11:1:11:25 | /* ... */ | comments1.cs:11:1:11:25 | /* ... */ | 1 | A multiline comment | /* A multiline comment */ | | comments1.cs:25:1:25:43 | /* ... */ | comments1.cs:25:1:25:15 | /* ... */ | 2 | This is a | /* This is a */ | From 40186db768584015b372fa37fe92ad0984272d1f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 15:51:38 +0100 Subject: [PATCH 109/429] Rename CommentPopulator --- .../Semmle.Extraction.CSharp/Analyser.cs | 9 +++++++-- .../{TriviaPopulator.cs => CommentPopulator.cs} | 6 +++--- .../Populators/CompilationUnitVisitor.cs | 16 ++++------------ 3 files changed, 14 insertions(+), 17 deletions(-) rename csharp/extractor/Semmle.Extraction.CSharp/Populators/{TriviaPopulator.cs => CommentPopulator.cs} (97%) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index b4076956c4f..fb03a6eee92 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -374,9 +374,14 @@ namespace Semmle.Extraction.CSharp if (!upToDate) { var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); - CompilationUnitVisitor.Extract(cx, tree.GetRoot()); + // Ensure that the file itself is populated in case the source file is totally empty + var root = tree.GetRoot(); + Extraction.Entities.File.Create(cx, root.SyntaxTree.FilePath); + + var csNode = (CSharpSyntaxNode)root; + csNode.Accept(new CompilationUnitVisitor(cx)); cx.PopulateAll(); - TriviaPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator); + CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator); cx.PopulateAll(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs similarity index 97% rename from csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs index 8aa99960a5b..0574a11db5f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TriviaPopulator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs @@ -7,9 +7,9 @@ using System; namespace Semmle.Extraction.CSharp.Populators { /// - /// Populators for trivias. + /// Populators for comments. /// - public static class TriviaPopulator + public static class CommentPopulator { public static void ExtractCommentBlocks(Context cx, ICommentGenerator gen) { @@ -33,7 +33,7 @@ namespace Semmle.Extraction.CSharp.Populators }); } - public static void ExtractTrivia(Context cx, SyntaxTrivia trivia) + public static void ExtractComment(Context cx, SyntaxTrivia trivia) { switch (trivia.Kind()) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs index 918366de186..bebdee933cd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Populators { internal class CompilationUnitVisitor : TypeOrNamespaceVisitor { - private CompilationUnitVisitor(Context cx) + public CompilationUnitVisitor(Context cx) : base(cx, cx.TrapWriter.Writer, null) { } public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) @@ -26,26 +26,18 @@ namespace Semmle.Extraction.CSharp.Populators // Gather comments: foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true)) { - TriviaPopulator.ExtractTrivia(cx, trivia); + CommentPopulator.ExtractComment(cx, trivia); } foreach (var trivia in compilationUnit.GetLeadingTrivia()) { - TriviaPopulator.ExtractTrivia(cx, trivia); + CommentPopulator.ExtractComment(cx, trivia); } foreach (var trivia in compilationUnit.GetTrailingTrivia()) { - TriviaPopulator.ExtractTrivia(cx, trivia); + CommentPopulator.ExtractComment(cx, trivia); } } - - public static void Extract(Context cx, SyntaxNode unit) - { - // Ensure that the file itself is populated in case the source file is totally empty - Extraction.Entities.File.Create(cx, unit.SyntaxTree.FilePath); - - ((CSharpSyntaxNode)unit).Accept(new CompilationUnitVisitor(cx)); - } } } From 8b9c6712d1ca9fceec88221eb7940e545574d7b4 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 15:52:12 +0100 Subject: [PATCH 110/429] Extract pragma warning directives --- .../Semmle.Extraction.CSharp/Analyser.cs | 1 + .../IPreprocessorDirective.cs | 4 ++ .../PragmaWarningDirective.cs | 43 +++++++++++++++++++ .../Populators/DirectiveVisitor.cs | 21 +++++++++ .../Semmle.Extraction.CSharp/Tuples.cs | 20 +++++++++ csharp/ql/src/csharp.qll | 1 + .../src/semmle/code/csharp/Preprocessor.qll | 30 +++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 22 +++++++++- .../comments/PragmaWarnings.expected | 7 +++ .../library-tests/comments/PragmaWarnings.ql | 9 ++++ 10 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs create mode 100644 csharp/ql/src/semmle/code/csharp/Preprocessor.qll create mode 100644 csharp/ql/test/library-tests/comments/PragmaWarnings.expected create mode 100644 csharp/ql/test/library-tests/comments/PragmaWarnings.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index fb03a6eee92..5aa4f452d92 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -380,6 +380,7 @@ namespace Semmle.Extraction.CSharp var csNode = (CSharpSyntaxNode)root; csNode.Accept(new CompilationUnitVisitor(cx)); + csNode.Accept(new DirectiveVisitor(cx)); cx.PopulateAll(); CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator); cx.PopulateAll(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs new file mode 100644 index 00000000000..89d2418258e --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs @@ -0,0 +1,4 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + internal interface IPreprocessorDirective { } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs new file mode 100644 index 00000000000..a96a49d76d3 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs @@ -0,0 +1,43 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class PragmaWarningDirective : FreshEntity, IPreprocessorDirective + { + private readonly PragmaWarningDirectiveTriviaSyntax trivia; + + public PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia) + : base(cx) + { + this.trivia = trivia; + TryPopulate(); + } + + protected override void Populate(TextWriter trapFile) + { + trapFile.pragma_warnings(this, trivia.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1); + + var childIndex = 0; + foreach (var code in trivia.ErrorCodes) + { + trapFile.pragma_warning_error_codes(this, code.ToString(), childIndex++); + } + + trapFile.preprocessor_directive_location(this, cx.Create(ReportingLocation)); + + if (!cx.Extractor.Standalone) + { + var assembly = Assembly.CreateOutputAssembly(cx); + trapFile.preprocessor_directive_assembly(this, assembly); + } + } + + public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation(); + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs new file mode 100644 index 00000000000..a4092e54455 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -0,0 +1,21 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class DirectiveVisitor : CSharpSyntaxWalker + { + private readonly Context cx; + + public DirectiveVisitor(Context cx) : base(SyntaxWalkerDepth.StructuredTrivia) + { + this.cx = cx; + } + + public override void VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node) + { + new Entities.PragmaWarningDirective(cx, node); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 630c2848e3d..8a6e570ff53 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -590,5 +590,25 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("using_static_directives", @using, type); } + + internal static void preprocessor_directive_location(this TextWriter trapFile, IPreprocessorDirective directive, Location location) + { + trapFile.WriteTuple("preprocessor_directive_location", directive, location); + } + + internal static void preprocessor_directive_assembly(this TextWriter trapFile, IPreprocessorDirective directive, Assembly assembly) + { + trapFile.WriteTuple("preprocessor_directive_assembly", directive, assembly); + } + + internal static void pragma_warnings(this TextWriter trapFile, PragmaWarningDirective pragma, int kind) + { + trapFile.WriteTuple("pragma_warnings", pragma, kind); + } + + internal static void pragma_warning_error_codes(this TextWriter trapFile, PragmaWarningDirective pragma, string errorCode, int child) + { + trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child); + } } } diff --git a/csharp/ql/src/csharp.qll b/csharp/ql/src/csharp.qll index 2a44f6e864a..3c821c9a443 100644 --- a/csharp/ql/src/csharp.qll +++ b/csharp/ql/src/csharp.qll @@ -19,6 +19,7 @@ import semmle.code.csharp.Type import semmle.code.csharp.Using import semmle.code.csharp.Variable import semmle.code.csharp.XML +import semmle.code.csharp.Preprocessor import semmle.code.csharp.exprs.Access import semmle.code.csharp.exprs.ArithmeticOperation import semmle.code.csharp.exprs.Assignment diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll new file mode 100644 index 00000000000..d432a0a3588 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -0,0 +1,30 @@ +/** + * Provides all preprocessor directive classes. + */ + +import Element + +class PreprocessorDirective extends Element, @preprocessor_directive { + override Location getALocation() { preprocessor_directive_location(this, result) } +} + +/** + * A `#pragma warning` directive. + */ +class PragmaWarningDirective extends PreprocessorDirective, @pragma_warning { + /** Holds if this is a `#pragma warning restore` directive. */ + predicate restore() { pragma_warnings(this, 1) } + + /** Holds if this is a `#pragma warning disable` directive. */ + predicate disable() { pragma_warnings(this, 0) } + + /** Holds if this directive specifies error codes. */ + predicate hasErrorCodes() { exists(string s | pragma_warning_error_codes(this, s, _)) } + + /** Gets a specified error code from this directive. */ + string getAnErrorCode() { pragma_warning_error_codes(this, result, _) } + + override string toString() { result = "#pragma warning ..." } + + override string getAPrimaryQlClass() { result = "PragmaWarningDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index efcd69e086a..3812d7ce9db 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -217,7 +217,7 @@ tokens( @element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration | @using_directive | @type_parameter_constraints | @external_element - | @xmllocatable | @asp_element | @namespace; + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; @declaration = @callable | @generic | @assignable | @namespace; @@ -331,6 +331,26 @@ using_directive_location( unique int id: @using_directive ref, int loc: @location ref); +@preprocessor_directive = @pragma_warning; + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_assembly( + unique int id: @preprocessor_directive ref, + int loc: @assembly ref); + /** TYPES **/ types( diff --git a/csharp/ql/test/library-tests/comments/PragmaWarnings.expected b/csharp/ql/test/library-tests/comments/PragmaWarnings.expected new file mode 100644 index 00000000000..ade1a86da1c --- /dev/null +++ b/csharp/ql/test/library-tests/comments/PragmaWarnings.expected @@ -0,0 +1,7 @@ +disable +| trivia.cs:12:1:12:35 | #pragma warning ... | +restore +| trivia.cs:23:1:23:23 | #pragma warning ... | +errorCodes +| trivia.cs:12:1:12:35 | #pragma warning ... | 414 | +| trivia.cs:12:1:12:35 | #pragma warning ... | CS3021 | diff --git a/csharp/ql/test/library-tests/comments/PragmaWarnings.ql b/csharp/ql/test/library-tests/comments/PragmaWarnings.ql new file mode 100644 index 00000000000..15d793b6392 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/PragmaWarnings.ql @@ -0,0 +1,9 @@ +import csharp + +query predicate disable(PragmaWarningDirective pragma) { pragma.disable() } + +query predicate restore(PragmaWarningDirective pragma) { pragma.restore() } + +query predicate errorCodes(PragmaWarningDirective pragma, string code) { + pragma.hasErrorCodes() and code = pragma.getAnErrorCode() +} From 94bf3467b72aa14cc6ca39ad99c3ba92a6c1cf1e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 16:59:14 +0100 Subject: [PATCH 111/429] Extract pragma checksum directives --- .../IPreprocessorDirective.cs | 4 -- .../PragmaChecksumDirective.cs | 18 +++++++++ .../PragmaWarningDirective.cs | 23 ++---------- .../PreprocessorDirective.cs | 37 +++++++++++++++++++ .../Populators/DirectiveVisitor.cs | 5 +++ .../Semmle.Extraction.CSharp/Tuples.cs | 14 ++++++- .../src/semmle/code/csharp/Preprocessor.qll | 18 +++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 8 +++- .../comments/PragmaChecksums.expected | 1 + .../library-tests/comments/PragmaChecksums.ql | 4 ++ 10 files changed, 105 insertions(+), 27 deletions(-) delete mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/PragmaChecksums.expected create mode 100644 csharp/ql/test/library-tests/comments/PragmaChecksums.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs deleted file mode 100644 index 89d2418258e..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IPreprocessorDirective.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Semmle.Extraction.CSharp.Entities -{ - internal interface IPreprocessorDirective { } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs new file mode 100644 index 00000000000..9de67176e54 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class PragmaChecksumDirective : PreprocessorDirective + { + public PragmaChecksumDirective(Context cx, PragmaChecksumDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.pragma_checksums(this, trivia.File.ToString(), trivia.Guid.ToString(), trivia.Bytes.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs index a96a49d76d3..4502fa4a87a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaWarningDirective.cs @@ -1,23 +1,18 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.Entities; using System.IO; namespace Semmle.Extraction.CSharp.Entities { - internal class PragmaWarningDirective : FreshEntity, IPreprocessorDirective + internal class PragmaWarningDirective : PreprocessorDirective { - private readonly PragmaWarningDirectiveTriviaSyntax trivia; - public PragmaWarningDirective(Context cx, PragmaWarningDirectiveTriviaSyntax trivia) - : base(cx) + : base(cx, trivia) { - this.trivia = trivia; - TryPopulate(); } - protected override void Populate(TextWriter trapFile) + protected override void PopulatePreprocessor(TextWriter trapFile) { trapFile.pragma_warnings(this, trivia.DisableOrRestoreKeyword.IsKind(SyntaxKind.DisableKeyword) ? 0 : 1); @@ -26,18 +21,6 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.pragma_warning_error_codes(this, code.ToString(), childIndex++); } - - trapFile.preprocessor_directive_location(this, cx.Create(ReportingLocation)); - - if (!cx.Extractor.Standalone) - { - var assembly = Assembly.CreateOutputAssembly(cx); - trapFile.preprocessor_directive_assembly(this, assembly); - } } - - public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation(); - - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs new file mode 100644 index 00000000000..e19ffe43549 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -0,0 +1,37 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal abstract class PreprocessorDirective : FreshEntity where TDirective : DirectiveTriviaSyntax + { + protected readonly TDirective trivia; + + protected PreprocessorDirective(Context cx, TDirective trivia) + : base(cx) + { + this.trivia = trivia; + TryPopulate(); + } + + protected sealed override void Populate(TextWriter trapFile) + { + PopulatePreprocessor(trapFile); + + trapFile.preprocessor_directive_location(this, cx.Create(ReportingLocation)); + + if (!cx.Extractor.Standalone) + { + var assembly = Assembly.CreateOutputAssembly(cx); + trapFile.preprocessor_directive_assembly(this, assembly); + } + } + + protected abstract void PopulatePreprocessor(TextWriter trapFile); + + public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => trivia.GetLocation(); + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index a4092e54455..c1d23ca5f0b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -17,5 +17,10 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.PragmaWarningDirective(cx, node); } + + public override void VisitPragmaChecksumDirectiveTrivia(PragmaChecksumDirectiveTriviaSyntax node) + { + new Entities.PragmaChecksumDirective(cx, node); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 8a6e570ff53..55060767806 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -1,3 +1,4 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CommentProcessing; using Semmle.Extraction.CSharp.Entities; using Semmle.Extraction.Entities; @@ -591,12 +592,16 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("using_static_directives", @using, type); } - internal static void preprocessor_directive_location(this TextWriter trapFile, IPreprocessorDirective directive, Location location) + internal static void preprocessor_directive_location(this TextWriter trapFile, + PreprocessorDirective directive, Location location) + where TDirective : DirectiveTriviaSyntax { trapFile.WriteTuple("preprocessor_directive_location", directive, location); } - internal static void preprocessor_directive_assembly(this TextWriter trapFile, IPreprocessorDirective directive, Assembly assembly) + internal static void preprocessor_directive_assembly(this TextWriter trapFile, + PreprocessorDirective directive, Assembly assembly) + where TDirective : DirectiveTriviaSyntax { trapFile.WriteTuple("preprocessor_directive_assembly", directive, assembly); } @@ -610,5 +615,10 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child); } + + internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, string file, string guid, string bytes) + { + trapFile.WriteTuple("pragma_checksums", pragma, file, guid, bytes); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index d432a0a3588..46e806aface 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -28,3 +28,21 @@ class PragmaWarningDirective extends PreprocessorDirective, @pragma_warning { override string getAPrimaryQlClass() { result = "PragmaWarningDirective" } } + +/** + * A `#pragma checksum` directive. + */ +class PragmaChecksumDirective extends PreprocessorDirective, @pragma_checksum { + /** Gets the file name of this directive. */ + string getFileName() { pragma_checksums(this, result, _, _) } + + /** Gets the GUID of this directive. */ + string getGuid() { pragma_checksums(this, _, result, _) } + + /** Gets the checksum bytes of this directive. */ + string getBytes() { pragma_checksums(this, _, _, result) } + + override string toString() { result = "#pragma checksum ..." } + + override string getAPrimaryQlClass() { result = "PragmaChecksumDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 3812d7ce9db..5530f36c85e 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -331,7 +331,13 @@ using_directive_location( unique int id: @using_directive ref, int loc: @location ref); -@preprocessor_directive = @pragma_warning; +@preprocessor_directive = @pragma_warning | @pragma_checksum; + +pragma_checksums( + unique int id: @pragma_checksum, + string file: string ref, + string guid: string ref, + string bytes: string ref); pragma_warnings( unique int id: @pragma_warning, diff --git a/csharp/ql/test/library-tests/comments/PragmaChecksums.expected b/csharp/ql/test/library-tests/comments/PragmaChecksums.expected new file mode 100644 index 00000000000..185e834cbdf --- /dev/null +++ b/csharp/ql/test/library-tests/comments/PragmaChecksums.expected @@ -0,0 +1 @@ +| trivia.cs:13:1:13:98 | #pragma checksum ... | "file.cs" | "{406EA660-64CF-4C82-B6F0-42D48172A799}" | "ab007f1d23d9" | diff --git a/csharp/ql/test/library-tests/comments/PragmaChecksums.ql b/csharp/ql/test/library-tests/comments/PragmaChecksums.ql new file mode 100644 index 00000000000..7d3f10ab3b5 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/PragmaChecksums.ql @@ -0,0 +1,4 @@ +import csharp + +from PragmaChecksumDirective p +select p, p.getFileName(), p.getGuid(), p.getBytes() From 9b405144ffb9949f99a3df121e1c888beb16d0a1 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 17:15:14 +0100 Subject: [PATCH 112/429] Extract define directives --- .../PreprocessorDirectives/DefineDirective.cs | 18 ++++++++++++++++++ .../Populators/DirectiveVisitor.cs | 5 +++++ .../Semmle.Extraction.CSharp/Tuples.cs | 5 +++++ .../ql/src/semmle/code/csharp/Preprocessor.qll | 12 ++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 6 +++++- .../comments/DefineDirectives.expected | 1 + .../library-tests/comments/DefineDirectives.ql | 4 ++++ 7 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/DefineDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/DefineDirectives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs new file mode 100644 index 00000000000..2ca967a4864 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/DefineDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class DefineDirective : PreprocessorDirective + { + public DefineDirective(Context cx, DefineDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_defines(this, trivia.Name.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index c1d23ca5f0b..69222935483 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -22,5 +22,10 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.PragmaChecksumDirective(cx, node); } + + public override void VisitDefineDirectiveTrivia(DefineDirectiveTriviaSyntax node) + { + new Entities.DefineDirective(cx, node); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 55060767806..9e14c8d32d2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -620,5 +620,10 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("pragma_checksums", pragma, file, guid, bytes); } + + internal static void directive_defines(this TextWriter trapFile, DefineDirective directive, string name) + { + trapFile.WriteTuple("directive_defines", directive, name); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 46e806aface..a5281da2241 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -46,3 +46,15 @@ class PragmaChecksumDirective extends PreprocessorDirective, @pragma_checksum { override string getAPrimaryQlClass() { result = "PragmaChecksumDirective" } } + +/** + * An `#define` directive. + */ +class DefineDirective extends PreprocessorDirective, @directive_define { + /** Gets the name of the preprocessor symbol that is being set by this directive. */ + string getName() { directive_defines(this, result) } + + override string toString() { result = "#define ..." } + + override string getAPrimaryQlClass() { result = "DefineDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 5530f36c85e..05e53c0042d 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -331,7 +331,11 @@ using_directive_location( unique int id: @using_directive ref, int loc: @location ref); -@preprocessor_directive = @pragma_warning | @pragma_checksum; +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define; + +directive_defines( + unique int id: @directive_define, + string name: string ref); pragma_checksums( unique int id: @pragma_checksum, diff --git a/csharp/ql/test/library-tests/comments/DefineDirectives.expected b/csharp/ql/test/library-tests/comments/DefineDirectives.expected new file mode 100644 index 00000000000..e58b3859d58 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/DefineDirectives.expected @@ -0,0 +1 @@ +| trivia.cs:4:1:4:13 | #define ... | DEBUG | diff --git a/csharp/ql/test/library-tests/comments/DefineDirectives.ql b/csharp/ql/test/library-tests/comments/DefineDirectives.ql new file mode 100644 index 00000000000..a27b18f9fbe --- /dev/null +++ b/csharp/ql/test/library-tests/comments/DefineDirectives.ql @@ -0,0 +1,4 @@ +import csharp + +from DefineDirective d +select d, d.getName() From 3740aba4a800b2a96d84ee90600902b31d85d969 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 19 Jan 2021 17:22:51 +0100 Subject: [PATCH 113/429] Extract undef directives --- .../UndefineDirective.cs | 18 ++++++++++++++++++ .../Populators/DirectiveVisitor.cs | 5 +++++ .../Semmle.Extraction.CSharp/Tuples.cs | 5 +++++ .../ql/src/semmle/code/csharp/Preprocessor.qll | 12 ++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 6 +++++- .../comments/UndefineDirectives.expected | 1 + .../comments/UndefineDirectives.ql | 4 ++++ 7 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/UndefineDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/UndefineDirectives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs new file mode 100644 index 00000000000..d4b976d50c0 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/UndefineDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class UndefineDirective : PreprocessorDirective + { + public UndefineDirective(Context cx, UndefDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_undefines(this, trivia.Name.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index 69222935483..07fd08965e0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -27,5 +27,10 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.DefineDirective(cx, node); } + + public override void VisitUndefDirectiveTrivia(UndefDirectiveTriviaSyntax node) + { + new Entities.UndefineDirective(cx, node); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 9e14c8d32d2..b55ef23b6f4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -625,5 +625,10 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("directive_defines", directive, name); } + + internal static void directive_undefines(this TextWriter trapFile, UndefineDirective directive, string name) + { + trapFile.WriteTuple("directive_undefines", directive, name); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index a5281da2241..174349e57d4 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -58,3 +58,15 @@ class DefineDirective extends PreprocessorDirective, @directive_define { override string getAPrimaryQlClass() { result = "DefineDirective" } } + +/** + * An `#undef` directive. + */ +class UndefineDirective extends PreprocessorDirective, @directive_undefine { + /** Gets the name of the preprocessor symbol that is being unset by this directive. */ + string getName() { directive_undefines(this, result) } + + override string toString() { result = "#undef ..." } + + override string getAPrimaryQlClass() { result = "UndefineDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 05e53c0042d..a026ea3d661 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -331,7 +331,11 @@ using_directive_location( unique int id: @using_directive ref, int loc: @location ref); -@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define; +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine; + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); directive_defines( unique int id: @directive_define, diff --git a/csharp/ql/test/library-tests/comments/UndefineDirectives.expected b/csharp/ql/test/library-tests/comments/UndefineDirectives.expected new file mode 100644 index 00000000000..016d2623f7d --- /dev/null +++ b/csharp/ql/test/library-tests/comments/UndefineDirectives.expected @@ -0,0 +1 @@ +| trivia.cs:6:1:6:12 | #undef ... | DEBUG | diff --git a/csharp/ql/test/library-tests/comments/UndefineDirectives.ql b/csharp/ql/test/library-tests/comments/UndefineDirectives.ql new file mode 100644 index 00000000000..72e992f9373 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/UndefineDirectives.ql @@ -0,0 +1,4 @@ +import csharp + +from UndefineDirective d +select d, d.getName() From 15c611e22f80aa4926158fc57ab6b0720e66d1cc Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 20 Jan 2021 08:55:41 +0100 Subject: [PATCH 114/429] Extract warning and error directives --- .../PreprocessorDirectives/ErrorDirective.cs | 18 ++++++++++++++ .../WarningDirective.cs | 18 ++++++++++++++ .../Populators/DirectiveVisitor.cs | 10 ++++++++ .../Semmle.Extraction.CSharp/Tuples.cs | 10 ++++++++ .../src/semmle/code/csharp/Preprocessor.qll | 24 +++++++++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 11 ++++++++- .../comments/ErrorDirectives.expected | 1 + .../library-tests/comments/ErrorDirectives.ql | 4 ++++ .../comments/WarningDirectives.expected | 1 + .../comments/WarningDirectives.ql | 4 ++++ 10 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/ErrorDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/ErrorDirectives.ql create mode 100644 csharp/ql/test/library-tests/comments/WarningDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/WarningDirectives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs new file mode 100644 index 00000000000..2917d077839 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ErrorDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class ErrorDirective : PreprocessorDirective + { + public ErrorDirective(Context cx, ErrorDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_errors(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs new file mode 100644 index 00000000000..1511be8d28c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/WarningDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class WarningDirective : PreprocessorDirective + { + public WarningDirective(Context cx, WarningDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_warnings(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index 07fd08965e0..7bafdac71b4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -32,5 +32,15 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.UndefineDirective(cx, node); } + + public override void VisitWarningDirectiveTrivia(WarningDirectiveTriviaSyntax node) + { + new Entities.WarningDirective(cx, node); + } + + public override void VisitErrorDirectiveTrivia(ErrorDirectiveTriviaSyntax node) + { + new Entities.ErrorDirective(cx, node); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index b55ef23b6f4..bcdacb8c3c1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -630,5 +630,15 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("directive_undefines", directive, name); } + + internal static void directive_warnings(this TextWriter trapFile, WarningDirective directive, string message) + { + trapFile.WriteTuple("directive_warnings", directive, message); + } + + internal static void directive_errors(this TextWriter trapFile, ErrorDirective directive, string message) + { + trapFile.WriteTuple("directive_errors", directive, message); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 174349e57d4..39dce043013 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -70,3 +70,27 @@ class UndefineDirective extends PreprocessorDirective, @directive_undefine { override string getAPrimaryQlClass() { result = "UndefineDirective" } } + +/** + * A `#warning` directive. + */ +class WarningDirective extends PreprocessorDirective, @directive_warning { + /** Gets the text of the warning. */ + string getMessage() { directive_warnings(this, result) } + + override string toString() { result = "#warning ..." } + + override string getAPrimaryQlClass() { result = "WarningDirective" } +} + +/** + * An `#error` directive. + */ +class ErrorDirective extends PreprocessorDirective, @directive_error { + /** Gets the text of the error. */ + string getMessage() { directive_errors(this, result) } + + override string toString() { result = "#error ..." } + + override string getAPrimaryQlClass() { result = "ErrorDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index a026ea3d661..b05630b6e9a 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -331,7 +331,16 @@ using_directive_location( unique int id: @using_directive ref, int loc: @location ref); -@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine; +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error; + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); directive_undefines( unique int id: @directive_undefine, diff --git a/csharp/ql/test/library-tests/comments/ErrorDirectives.expected b/csharp/ql/test/library-tests/comments/ErrorDirectives.expected new file mode 100644 index 00000000000..656b501c904 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/ErrorDirectives.expected @@ -0,0 +1 @@ +| trivia.cs:72:1:72:41 | #error ... | NOTDEBUG is defined or TEST is not | diff --git a/csharp/ql/test/library-tests/comments/ErrorDirectives.ql b/csharp/ql/test/library-tests/comments/ErrorDirectives.ql new file mode 100644 index 00000000000..dbfbb986a4c --- /dev/null +++ b/csharp/ql/test/library-tests/comments/ErrorDirectives.ql @@ -0,0 +1,4 @@ +import csharp + +from ErrorDirective d +select d, d.getMessage() diff --git a/csharp/ql/test/library-tests/comments/WarningDirectives.expected b/csharp/ql/test/library-tests/comments/WarningDirectives.expected new file mode 100644 index 00000000000..105119a8127 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/WarningDirectives.expected @@ -0,0 +1 @@ +| trivia.cs:66:1:66:25 | #warning ... | DEBUG is defined | diff --git a/csharp/ql/test/library-tests/comments/WarningDirectives.ql b/csharp/ql/test/library-tests/comments/WarningDirectives.ql new file mode 100644 index 00000000000..0b1dedf1d77 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/WarningDirectives.ql @@ -0,0 +1,4 @@ +import csharp + +from WarningDirective d +select d, d.getMessage() From 4bb8b6c9924cbe9767818acc7302cfb718999766 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 20 Jan 2021 09:34:18 +0100 Subject: [PATCH 115/429] Extract nullable directives --- .../NullableDirective.cs | 35 ++++++++++++++ .../Populators/DirectiveVisitor.cs | 5 ++ .../Semmle.Extraction.CSharp/Tuples.cs | 5 ++ .../src/semmle/code/csharp/Preprocessor.qll | 46 +++++++++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 7 ++- .../comments/NullableDirectives.expected | 21 +++++++++ .../comments/NullableDirectives.ql | 11 +++++ 7 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/NullableDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/NullableDirectives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs new file mode 100644 index 00000000000..e6bb4e79fed --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/NullableDirective.cs @@ -0,0 +1,35 @@ +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class NullableDirective : PreprocessorDirective + { + public NullableDirective(Context cx, NullableDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + var setting = trivia.SettingToken.Kind() switch + { + SyntaxKind.DisableKeyword => 0, + SyntaxKind.EnableKeyword => 1, + SyntaxKind.RestoreKeyword => 2, + _ => throw new InternalError(trivia, "Unhandled setting token kind") + }; + + var target = trivia.TargetToken.Kind() switch + { + SyntaxKind.None => 0, + SyntaxKind.AnnotationsKeyword => 1, + SyntaxKind.WarningsKeyword => 2, + _ => throw new InternalError(trivia, "Unhandled target token kind") + }; + + trapFile.directive_nullables(this, setting, target); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index 7bafdac71b4..d16b4ca041b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -42,5 +42,10 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.ErrorDirective(cx, node); } + + public override void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) + { + new Entities.NullableDirective(cx, node); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index bcdacb8c3c1..4b834d42ae1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -640,5 +640,10 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("directive_errors", directive, message); } + + internal static void directive_nullables(this TextWriter trapFile, NullableDirective directive, int setting, int target) + { + trapFile.WriteTuple("directive_nullables", directive, setting, target); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 39dce043013..8996756d069 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -94,3 +94,49 @@ class ErrorDirective extends PreprocessorDirective, @directive_error { override string getAPrimaryQlClass() { result = "ErrorDirective" } } + +/** + * A `#nullable` directive. + */ +class NullableDirective extends PreprocessorDirective, @directive_nullable { + /** Holds if this is a `#nullable disable` directive. */ + predicate disable() { directive_nullables(this, 0, _) } + + /** Holds if this is a `#nullable enable` directive. */ + predicate enable() { directive_nullables(this, 1, _) } + + /** Holds if this is a `#nullable restore` directive. */ + predicate restore() { directive_nullables(this, 2, _) } + + /** Holds if this directive targets all nullable contexts. */ + predicate targetsAll() { directive_nullables(this, _, 0) } + + /** Holds if this directive targets nullable annotation context. */ + predicate targetsAnnotations() { directive_nullables(this, _, 1) } + + /** Holds if this directive targets nullable warning context. */ + predicate targetsWarnings() { directive_nullables(this, _, 2) } + + /** Gets the succeeding `#nullable` directive in the file, if any. */ + NullableDirective getSuccNullableDirective() { + result = + rank[1](NullableDirective next | + next.getFile() = this.getFile() and + next.getLocation().getStartLine() > this.getLocation().getStartLine() + | + next order by next.getLocation().getStartLine() + ) + } + + /** Holds if there is a succeeding `#nullable` directive in the file. */ + predicate hasSuccNullableDirective() { + exists(NullableDirective other | + other.getFile() = this.getFile() and + other.getLocation().getStartLine() > this.getLocation().getStartLine() + ) + } + + override string toString() { result = "#nullable ..." } + + override string getAPrimaryQlClass() { result = "NullableDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index b05630b6e9a..e815200408e 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -332,7 +332,12 @@ using_directive_location( int loc: @location ref); @preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning - | @directive_error; + | @directive_error | @directive_nullable; + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ directive_warnings( unique int id: @directive_warning, diff --git a/csharp/ql/test/library-tests/comments/NullableDirectives.expected b/csharp/ql/test/library-tests/comments/NullableDirectives.expected new file mode 100644 index 00000000000..bbf13afa63b --- /dev/null +++ b/csharp/ql/test/library-tests/comments/NullableDirectives.expected @@ -0,0 +1,21 @@ +nullables +| trivia.cs:49:1:49:82 | #nullable ... | 0 | 0 | +| trivia.cs:50:1:50:80 | #nullable ... | 1 | 0 | +| trivia.cs:51:1:51:94 | #nullable ... | 2 | 0 | +| trivia.cs:52:1:52:81 | #nullable ... | 0 | 1 | +| trivia.cs:53:1:53:79 | #nullable ... | 1 | 1 | +| trivia.cs:54:1:54:93 | #nullable ... | 2 | 1 | +| trivia.cs:55:1:55:75 | #nullable ... | 0 | 2 | +| trivia.cs:56:1:56:73 | #nullable ... | 1 | 2 | +| trivia.cs:57:1:57:87 | #nullable ... | 2 | 2 | +succ +| trivia.cs:49:1:49:82 | #nullable ... | trivia.cs:50:1:50:80 | #nullable ... | +| trivia.cs:50:1:50:80 | #nullable ... | trivia.cs:51:1:51:94 | #nullable ... | +| trivia.cs:51:1:51:94 | #nullable ... | trivia.cs:52:1:52:81 | #nullable ... | +| trivia.cs:52:1:52:81 | #nullable ... | trivia.cs:53:1:53:79 | #nullable ... | +| trivia.cs:53:1:53:79 | #nullable ... | trivia.cs:54:1:54:93 | #nullable ... | +| trivia.cs:54:1:54:93 | #nullable ... | trivia.cs:55:1:55:75 | #nullable ... | +| trivia.cs:55:1:55:75 | #nullable ... | trivia.cs:56:1:56:73 | #nullable ... | +| trivia.cs:56:1:56:73 | #nullable ... | trivia.cs:57:1:57:87 | #nullable ... | +last +| trivia.cs:57:1:57:87 | #nullable ... | diff --git a/csharp/ql/test/library-tests/comments/NullableDirectives.ql b/csharp/ql/test/library-tests/comments/NullableDirectives.ql new file mode 100644 index 00000000000..a5312df39e9 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/NullableDirectives.ql @@ -0,0 +1,11 @@ +import csharp + +query predicate nullables(NullableDirective d, int setting, int target) { + directive_nullables(d, setting, target) +} + +query predicate succ(NullableDirective d, NullableDirective succ) { + d.getSuccNullableDirective() = succ +} + +query predicate last(NullableDirective d) { not d.hasSuccNullableDirective() } From fe0a494bab546ba05458a68bc3ca756cc5033e3b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 20 Jan 2021 10:06:05 +0100 Subject: [PATCH 116/429] Extract line directives --- .../PreprocessorDirectives/LineDirective.cs | 34 +++++++++ .../Populators/DirectiveVisitor.cs | 5 ++ .../Semmle.Extraction.CSharp/Tuples.cs | 10 +++ .../src/semmle/code/csharp/Preprocessor.qll | 69 +++++++++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 11 ++- .../comments/LineDirectives.expected | 13 ++++ .../library-tests/comments/LineDirectives.ql | 13 ++++ .../ql/test/library-tests/comments/trivia.cs | 2 +- 8 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/LineDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/LineDirectives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs new file mode 100644 index 00000000000..2ca34d6c7a1 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs @@ -0,0 +1,34 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class LineDirective : PreprocessorDirective + { + public LineDirective(Context cx, LineDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + var type = trivia.Line.Kind() switch + { + SyntaxKind.DefaultKeyword => 0, + SyntaxKind.HiddenKeyword => 1, + SyntaxKind.NumericLiteralToken => 2, + _ => throw new InternalError(trivia, "Unhandled line token kind") + }; + + trapFile.directive_lines(this, type); + + if (trivia.Line.IsKind(SyntaxKind.NumericLiteralToken)) + { + var value = (int)trivia.Line.Value; + trapFile.directive_line_values(this, value, trivia.File.ValueText); + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index d16b4ca041b..baa52ec7f03 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -47,5 +47,10 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.NullableDirective(cx, node); } + + public override void VisitLineDirectiveTrivia(LineDirectiveTriviaSyntax node) + { + new Entities.LineDirective(cx, node); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 4b834d42ae1..1ee94ff1426 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -645,5 +645,15 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("directive_nullables", directive, setting, target); } + + internal static void directive_lines(this TextWriter trapFile, LineDirective directive, int kind) + { + trapFile.WriteTuple("directive_lines", directive, kind); + } + + internal static void directive_line_values(this TextWriter trapFile, LineDirective directive, int line, string file) + { + trapFile.WriteTuple("directive_line_values", directive, line, file); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 8996756d069..983e58da2cb 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -140,3 +140,72 @@ class NullableDirective extends PreprocessorDirective, @directive_nullable { override string getAPrimaryQlClass() { result = "NullableDirective" } } + +/** + * A `#line` directive, such as `#line default`, `#line hidden`, or `#line` + * directive with line number. + */ +class LineDirective extends PreprocessorDirective, @directive_line { + /** Gets the succeeding `#line` directive in the file, if any. */ + LineDirective getSuccLineDirective() { + result = + rank[1](LineDirective next | + next.getFile() = this.getFile() and + next.getLocation().getStartLine() > this.getLocation().getStartLine() + | + next order by next.getLocation().getStartLine() + ) + } + + /** Holds if there is a succeeding `#line` directive in the file. */ + predicate hasSuccLineDirective() { + exists(LineDirective other | + other.getFile() = this.getFile() and + other.getLocation().getStartLine() > this.getLocation().getStartLine() + ) + } + + override string toString() { result = "#line ..." } + + override string getAPrimaryQlClass() { result = "LineDirective" } +} + +/** + * A `#line default` directive. + */ +class DefaultLineDirective extends LineDirective { + DefaultLineDirective() { directive_lines(this, 0) } + + override string toString() { result = "#line default" } + + override string getAPrimaryQlClass() { result = "DefaultLineDirective" } +} + +/** + * A `#line hidden` directive. + */ +class HiddenLineDirective extends LineDirective { + HiddenLineDirective() { directive_lines(this, 1) } + + override string toString() { result = "#line hidden" } + + override string getAPrimaryQlClass() { result = "HiddenLineDirective" } +} + +/** + * A numeric `#line` directive, such as `#line 200 file` + */ +class NumericLineDirective extends LineDirective { + NumericLineDirective() { directive_lines(this, 2) } + + /** Gets the line number of this directive. */ + int getLine() { directive_line_values(this, result, _) } + + /** Holds if this directive specifies a file name. */ + predicate hasFileName() { this.getFileName() != "" } + + /** Gets the file name of this directive. */ + string getFileName() { directive_line_values(this, _, result) } + + override string getAPrimaryQlClass() { result = "NumericLineDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index e815200408e..92e9947958b 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -332,7 +332,16 @@ using_directive_location( int loc: @location ref); @preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning - | @directive_error | @directive_nullable; + | @directive_error | @directive_nullable | @directive_line; + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric */ + +directive_line_values( + unique int id: @directive_line ref, + int line: int ref, + string file: string ref); directive_nullables( unique int id: @directive_nullable, diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.expected b/csharp/ql/test/library-tests/comments/LineDirectives.expected new file mode 100644 index 00000000000..ae79e53d1b4 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/LineDirectives.expected @@ -0,0 +1,13 @@ +default +| trivia.cs:21:1:21:13 | #line default | +hidden +| trivia.cs:25:1:25:38 | #line hidden | +lines +| trivia.cs:18:1:18:19 | #line ... | 200 | Special | +| trivia.cs:27:1:27:9 | #line ... | 300 | | +succ +| trivia.cs:18:1:18:19 | #line ... | trivia.cs:21:1:21:13 | #line default | +| trivia.cs:21:1:21:13 | #line default | trivia.cs:25:1:25:38 | #line hidden | +| trivia.cs:25:1:25:38 | #line hidden | trivia.cs:27:1:27:9 | #line ... | +last +| trivia.cs:27:1:27:9 | #line ... | diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.ql b/csharp/ql/test/library-tests/comments/LineDirectives.ql new file mode 100644 index 00000000000..db05488911a --- /dev/null +++ b/csharp/ql/test/library-tests/comments/LineDirectives.ql @@ -0,0 +1,13 @@ +import csharp + +query predicate default(DefaultLineDirective line) { any() } + +query predicate hidden(HiddenLineDirective line) { any() } + +query predicate lines(NumericLineDirective line, int l, string file) { + line.getLine() = l and line.getFileName() = file +} + +query predicate succ(LineDirective d, LineDirective succ) { d.getSuccLineDirective() = succ } + +query predicate last(LineDirective d) { not d.hasSuccLineDirective() } diff --git a/csharp/ql/test/library-tests/comments/trivia.cs b/csharp/ql/test/library-tests/comments/trivia.cs index e22ddf77a63..69aea425499 100644 --- a/csharp/ql/test/library-tests/comments/trivia.cs +++ b/csharp/ql/test/library-tests/comments/trivia.cs @@ -24,7 +24,7 @@ class Tr1 float f; #line hidden // numbering not affected string s; -#line default +#line 300 double d; } } From a5d18f9b6882e8f99c55deb667e482f8aa53829d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 20 Jan 2021 11:07:24 +0100 Subject: [PATCH 117/429] Extract region directives --- .../EndRegionDirective.cs | 23 ++++++++++++++++ .../PreprocessorDirectives/RegionDirective.cs | 18 +++++++++++++ .../Populators/DirectiveVisitor.cs | 23 ++++++++++++++++ .../Semmle.Extraction.CSharp/Tuples.cs | 15 +++++++++++ .../src/semmle/code/csharp/Preprocessor.qll | 27 +++++++++++++++++++ csharp/ql/src/semmlecode.csharp.dbscheme | 14 +++++++++- .../comments/RegionDirectives.expected | 6 +++++ .../comments/RegionDirectives.ql | 8 ++++++ 8 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/RegionDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/RegionDirectives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs new file mode 100644 index 00000000000..a320c89028c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs @@ -0,0 +1,23 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class EndRegionDirective : PreprocessorDirective + { + public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_endregions(this); + } + + internal static void WriteRegionBlock(Context cx, RegionDirective region, EndRegionDirective endregion) + { + cx.TrapWriter.Writer.regions(region, endregion); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs new file mode 100644 index 00000000000..28a707ee4de --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class RegionDirective : PreprocessorDirective + { + public RegionDirective(Context cx, RegionDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_regions(this, trivia.EndOfDirectiveToken.LeadingTrivia.ToString()); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index baa52ec7f03..a825ecead61 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; +using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -52,5 +54,26 @@ namespace Semmle.Extraction.CSharp.Populators { new Entities.LineDirective(cx, node); } + + private readonly Stack regionStarts = new Stack(); + + public override void VisitRegionDirectiveTrivia(RegionDirectiveTriviaSyntax node) + { + var region = new Entities.RegionDirective(cx, node); + regionStarts.Push(region); + } + + public override void VisitEndRegionDirectiveTrivia(EndRegionDirectiveTriviaSyntax node) + { + var endregion = new Entities.EndRegionDirective(cx, node); + if (regionStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start region", null, + Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + var start = regionStarts.Pop(); + Entities.EndRegionDirective.WriteRegionBlock(cx, start, endregion); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 1ee94ff1426..1eebf07c37f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -655,5 +655,20 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("directive_line_values", directive, line, file); } + + internal static void directive_regions(this TextWriter trapFile, RegionDirective directive, string name) + { + trapFile.WriteTuple("directive_regions", directive, name); + } + + internal static void directive_endregions(this TextWriter trapFile, EndRegionDirective directive) + { + trapFile.WriteTuple("directive_endregions", directive); + } + + internal static void regions(this TextWriter trapFile, RegionDirective start, EndRegionDirective end) + { + trapFile.WriteTuple("regions", start, end); + } } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 983e58da2cb..10397230f2e 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -209,3 +209,30 @@ class NumericLineDirective extends LineDirective { override string getAPrimaryQlClass() { result = "NumericLineDirective" } } + +/** + * A `#region` directive. + */ +class RegionDirective extends PreprocessorDirective, @directive_region { + /** Gets the name of this region. */ + string getName() { directive_regions(this, result) } + + /** Gets the closing `#endregion` directive. */ + EndRegionDirective getEnd() { regions(this, result) } + + override string toString() { result = "#region ..." } + + override string getAPrimaryQlClass() { result = "RegionDirective" } +} + +/** + * A `#endregion` directive. + */ +class EndRegionDirective extends PreprocessorDirective, @directive_endregion { + /** Gets the opening `#region` directive. */ + RegionDirective getStart() { regions(result, this) } + + override string toString() { result = "#endregion" } + + override string getAPrimaryQlClass() { result = "EndRegionDirective" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 92e9947958b..ad723e09a4d 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -332,7 +332,19 @@ using_directive_location( int loc: @location ref); @preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning - | @directive_error | @directive_nullable | @directive_line; + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion; + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +directive_endregions( + unique int id: @directive_endregion); + +#keyset[start, end] +regions( + unique int start: @directive_region ref, + unique int end: @directive_endregion ref); directive_lines( unique int id: @directive_line, diff --git a/csharp/ql/test/library-tests/comments/RegionDirectives.expected b/csharp/ql/test/library-tests/comments/RegionDirectives.expected new file mode 100644 index 00000000000..aead68e7ff0 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/RegionDirectives.expected @@ -0,0 +1,6 @@ +regionDirectives +| trivia.cs:36:9:36:22 | #region ... | fields | trivia.cs:41:9:41:18 | #endregion | +| trivia.cs:38:9:38:22 | #region ... | nested | trivia.cs:40:9:40:18 | #endregion | +endregions +| trivia.cs:40:9:40:18 | #endregion | trivia.cs:38:9:38:22 | #region ... | +| trivia.cs:41:9:41:18 | #endregion | trivia.cs:36:9:36:22 | #region ... | diff --git a/csharp/ql/test/library-tests/comments/RegionDirectives.ql b/csharp/ql/test/library-tests/comments/RegionDirectives.ql new file mode 100644 index 00000000000..9b1296819f2 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/RegionDirectives.ql @@ -0,0 +1,8 @@ +import csharp + +query predicate regionDirectives(RegionDirective d, string name, EndRegionDirective end) { + d.getName() = name and + d.getEnd() = end +} + +query predicate endregions(EndRegionDirective d, RegionDirective start) { d.getStart() = start } From 41fbce0ad00899ce5bb791a911a9ab93e0fad631 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 20 Jan 2021 15:21:36 +0100 Subject: [PATCH 118/429] Extract #if directives --- .../Entities/Expression.cs | 38 +++- .../Entities/Expressions/DefineSymbol.cs | 18 ++ .../Entities/Expressions/Literal.cs | 5 + .../Entities/Expressions/Name.cs | 12 +- .../PreprocessorDirectives/ElifDirective.cs | 22 +++ .../PreprocessorDirectives/ElseDirective.cs | 18 ++ .../PreprocessorDirectives/EndIfDirective.cs | 18 ++ .../IIfSiblingDirective.cs | 4 + .../PreprocessorDirectives/IfDirective.cs | 40 ++++ .../PreprocessorDirectives/RegionDirective.cs | 1 + .../Kinds/ExprKind.cs | 2 + .../Populators/DirectiveVisitor.cs | 47 +++++ .../Semmle.Extraction.CSharp/Tuples.cs | 38 ++++ .../src/semmle/code/csharp/Preprocessor.qll | 92 +++++++++ csharp/ql/src/semmle/code/csharp/PrintAst.qll | 2 + .../ql/src/semmle/code/csharp/exprs/Expr.qll | 18 ++ csharp/ql/src/semmlecode.csharp.dbscheme | 41 +++- .../comments/IfDirectives.expected | 19 ++ .../library-tests/comments/IfDirectives.ql | 33 ++++ .../library-tests/comments/PrintAst.expected | 175 ++++++++++++++++++ .../library-tests/comments/PrintAst.qlref | 1 + 21 files changed, 639 insertions(+), 5 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs create mode 100644 csharp/ql/test/library-tests/comments/IfDirectives.expected create mode 100644 csharp/ql/test/library-tests/comments/IfDirectives.ql create mode 100644 csharp/ql/test/library-tests/comments/PrintAst.expected create mode 100644 csharp/ql/test/library-tests/comments/PrintAst.qlref diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 9d701d242a3..5829bbffa9e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -529,7 +529,17 @@ namespace Semmle.Extraction.CSharp.Entities get { var c = Model.GetConstantValue(Node); - return c.HasValue ? Expression.ValueAsString(c.Value) : null; + if (c.HasValue) + { + return Expression.ValueAsString(c.Value); + } + + if (TryGetBoolValueInsideIfDirective(out var val)) + { + return Expression.ValueAsString(val); + } + + return null; } } @@ -593,5 +603,31 @@ namespace Semmle.Extraction.CSharp.Entities } public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; + + public bool IsInsideIfDirective() + { + return Node.Ancestors().Any(a => a is ElifDirectiveTriviaSyntax || a is IfDirectiveTriviaSyntax); + } + + public bool TryGetBoolValueInsideIfDirective(out bool val) + { + var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression); + var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression); + + if (!isTrue && !isFalse) + { + val = false; + return false; + } + + if (!IsInsideIfDirective()) + { + val = false; + return false; + } + + val = isTrue; + return true; + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs new file mode 100644 index 00000000000..d0111c010b2 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/DefineSymbol.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.Kinds; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities.Expressions +{ + internal class DefineSymbol : Expression + { + private DefineSymbol(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.DEFINE_SYMBOL)) { } + + public static Expression Create(ExpressionNodeInfo info) => new DefineSymbol(info).TryPopulate(); + + protected override void PopulateExpression(TextWriter trapFile) + { + trapFile.directive_define_symbols(this, Syntax.Identifier.Text); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs index ad63cc26ac6..d91f426cfd7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs @@ -25,6 +25,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.NULL_LITERAL; } + if (info.TryGetBoolValueInsideIfDirective(out var _)) + { + return ExprKind.BOOL_LITERAL; + } + var type = info.Type?.Symbol; return GetExprKind(type, info.Node, info.Context); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs index d44c85d6ddc..d74afd16329 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Linq; namespace Semmle.Extraction.CSharp.Entities.Expressions @@ -26,8 +27,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (target == null) { - info.Context.ModelError(info.Node, "Failed to resolve name"); - return new Unknown(info); + if (info.IsInsideIfDirective()) + { + return DefineSymbol.Create(info); + } + else + { + info.Context.ModelError(info.Node, "Failed to resolve name"); + return new Unknown(info); + } } // There is a very strange bug in Microsoft.CodeAnalysis whereby diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs new file mode 100644 index 00000000000..26314244ac6 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class ElifDirective : PreprocessorDirective, IIfSiblingDirective, IExpressionParentEntity + { + public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + public bool IsTopLevelParent => true; + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue); + + Expression.Create(cx, trivia.Condition, this, 0); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs new file mode 100644 index 00000000000..48c786627ac --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class ElseDirective : PreprocessorDirective, IIfSiblingDirective + { + public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_elses(this, trivia.BranchTaken); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs new file mode 100644 index 00000000000..85d5c89f353 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs @@ -0,0 +1,18 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class EndIfDirective : PreprocessorDirective + { + public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_endifs(this); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs new file mode 100644 index 00000000000..7a849962f09 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IIfSiblingDirective.cs @@ -0,0 +1,4 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + internal interface IIfSiblingDirective { } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs new file mode 100644 index 00000000000..fc9af188c1d --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs @@ -0,0 +1,40 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Generic; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class IfDirective : PreprocessorDirective, IExpressionParentEntity + { + private readonly List branches = new List(); + + public IfDirective(Context cx, IfDirectiveTriviaSyntax trivia) + : base(cx, trivia) + { + } + + public bool IsTopLevelParent => true; + + protected override void PopulatePreprocessor(TextWriter trapFile) + { + trapFile.directive_ifs(this, trivia.BranchTaken, trivia.ConditionValue); + + Expression.Create(cx, trivia.Condition, this, 0); + } + + internal void Add(IIfSiblingDirective branch) + { + branches.Add(branch); + } + + internal void WriteBranches(EndIfDirective endif) + { + cx.TrapWriter.Writer.directive_if_endif(this, endif); + var siblings = 0; + foreach (var branch in branches) + { + cx.TrapWriter.Writer.directive_if_siblings(this, branch, siblings++); + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs index 28a707ee4de..b2f017688a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/RegionDirective.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; using System.IO; namespace Semmle.Extraction.CSharp.Entities diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs index ee1185da30d..292e8c47d98 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs @@ -124,5 +124,7 @@ namespace Semmle.Extraction.Kinds AND_PATTERN = 127, OR_PATTERN = 128, FUNCTION_POINTER_INVOCATION = 129, + + DEFINE_SYMBOL = 999 } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index a825ecead61..074441a70cb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -75,5 +75,52 @@ namespace Semmle.Extraction.CSharp.Populators var start = regionStarts.Pop(); Entities.EndRegionDirective.WriteRegionBlock(cx, start, endregion); } + + private readonly Stack ifStarts = new Stack(); + + public override void VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node) + { + var ifStart = new Entities.IfDirective(cx, node); + ifStarts.Push(ifStart); + } + + public override void VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node) + { + var endif = new Entities.EndIfDirective(cx, node); + if (ifStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start if", null, + Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + var start = ifStarts.Pop(); + start.WriteBranches(endif); + } + + public override void VisitElifDirectiveTrivia(ElifDirectiveTriviaSyntax node) + { + var elif = new Entities.ElifDirective(cx, node); + if (ifStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start if", null, + Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + var start = ifStarts.Peek(); + start.Add(elif); + } + + public override void VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node) + { + var elseDirective = new Entities.ElseDirective(cx, node); + if (ifStarts.Count == 0) + { + cx.ExtractionError("Couldn't find start if", null, + Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + return; + } + var start = ifStarts.Peek(); + start.Add(elseDirective); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 1eebf07c37f..19b730f7cc0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -1,6 +1,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CommentProcessing; using Semmle.Extraction.CSharp.Entities; +using Semmle.Extraction.CSharp.Entities.Expressions; using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; using Semmle.Util; @@ -670,5 +671,42 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("regions", start, end); } + + internal static void directive_ifs(this TextWriter trapFile, IfDirective directive, bool branchTaken, bool conditionValue) + { + trapFile.WriteTuple("directive_ifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0); + } + + internal static void directive_elifs(this TextWriter trapFile, ElifDirective directive, bool branchTaken, bool conditionValue) + { + trapFile.WriteTuple("directive_elifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0); + } + + internal static void directive_elses(this TextWriter trapFile, ElseDirective directive, bool branchTaken) + { + trapFile.WriteTuple("directive_elses", directive, branchTaken ? 1 : 0); + } + + internal static void directive_endifs(this TextWriter trapFile, EndIfDirective directive) + { + trapFile.WriteTuple("directive_endifs", directive); + } + + internal static void directive_if_endif(this TextWriter trapFile, IfDirective start, EndIfDirective end) + { + trapFile.WriteTuple("directive_if_endif", start, end); + } + + internal static void directive_if_siblings(this TextWriter trapFile, IfDirective start, IIfSiblingDirective siblingDirective, int index) + { + trapFile.WriteTuple("directive_if_siblings", start, siblingDirective, index); + } + + internal static void directive_define_symbols(this TextWriter trapFile, DefineSymbol symb, string name) + { + trapFile.WriteTuple("directive_define_symbols", symb, name); + } + + } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 10397230f2e..1f23275a7a7 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -236,3 +236,95 @@ class EndRegionDirective extends PreprocessorDirective, @directive_endregion { override string getAPrimaryQlClass() { result = "EndRegionDirective" } } + +/** + * A branching preprocessor directive, such as `IfDirective`, `ElifDirective`, or + * `ElseDirective`. + */ +class BranchDirective extends PreprocessorDirective { + /** Holds if the branch is taken by the preprocessor. */ + predicate branchTaken() { none() } +} + +/** + * A preprocessor directive with a branching condition, such as `IfDirective` or + * `ElifDirective`. + */ +class ConditionalDirective extends BranchDirective { + /** Gets the condition. */ + Expr getCondition() { result = this.getChild(0) } + + /** Holds if the condition is matched. */ + predicate conditionMatched() { none() } +} + +/** + * An `#if` preprocessor directive. + */ +class IfDirective extends ConditionalDirective, @directive_if { + override predicate branchTaken() { directive_ifs(this, 1, _) } + + override predicate conditionMatched() { directive_ifs(this, _, 1) } + + /** Gets the closing `#endif` preprocessor directive. */ + EndifDirective getEndifDirective() { directive_if_endif(this, result) } + + /** Gets the sibling `#elif` or `#else` preprocessor directive at index `sibling`. */ + BranchDirective getSiblingDirective(int sibling) { directive_if_siblings(this, result, sibling) } + + /** Gets a sibling `#elif` or `#else` preprocessor directive. */ + BranchDirective getASiblingDirective() { result = getSiblingDirective(_) } + + override string toString() { result = "#if ..." } + + override string getAPrimaryQlClass() { result = "IfDirective" } +} + +/** + * An `#elif` preprocessor directive. + */ +class ElifDirective extends ConditionalDirective, @directive_elif { + override predicate branchTaken() { directive_elifs(this, 1, _) } + + override predicate conditionMatched() { directive_elifs(this, _, 1) } + + /** Gets the opening `#if` preprocessor directive. */ + IfDirective getIfDirective() { directive_if_siblings(result, this, _) } + + /** Gets the successive branching preprocessor directive (`#elif` or `#else`), if any. */ + BranchDirective getSuccSiblingDirective() { + exists(IfDirective i, int index | + directive_if_siblings(i, this, index) and directive_if_siblings(i, result, index + 1) + ) + } + + override string toString() { result = "#elif ..." } + + override string getAPrimaryQlClass() { result = "ElifDirective" } +} + +/** + * An `#else` preprocessor directive. + */ +class ElseDirective extends BranchDirective, @directive_else { + /** Gets the opening `#if` preprocessor directive. */ + IfDirective getIfDirective() { directive_if_siblings(result, this, _) } + + override predicate branchTaken() { directive_elses(this, 1) } + + override string toString() { result = "#else" } + + override string getAPrimaryQlClass() { result = "ElseDirective" } +} + +/** + * An `#endif` preprocessor directive. + */ +class EndifDirective extends PreprocessorDirective, @directive_endif { + /** Gets the opening `#if` preprocessor directive. */ + IfDirective getIfDirective() { directive_if_endif(result, this) } + + override string toString() { result = "#endif" } + + override string getAPrimaryQlClass() { result = "EndifDirective" } +} diff --git a/csharp/ql/src/semmle/code/csharp/PrintAst.qll b/csharp/ql/src/semmle/code/csharp/PrintAst.qll index 63ff928f9fc..a4ab6f7632c 100644 --- a/csharp/ql/src/semmle/code/csharp/PrintAst.qll +++ b/csharp/ql/src/semmle/code/csharp/PrintAst.qll @@ -48,6 +48,8 @@ private predicate isNotNeeded(Element e) { or e instanceof TupleType or + e instanceof ConditionalDirective + or isNotNeeded(e.(Declaration).getDeclaringType()) or isNotNeeded(e.(Parameter).getDeclaringElement()) diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 4078557f366..5a954b7a925 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -1134,3 +1134,21 @@ class SuppressNullableWarningExpr extends Expr, @suppress_nullable_warning_expr override string getAPrimaryQlClass() { result = "SuppressNullableWarningExpr" } } + +/** + * A preprocessor symbol inside an expression, such as DEBUG in line 2 + * ```csharp + * #define DEBUG + * #if (DEBUG == true) + * Console.WriteLine("Debug version"); + * #endif + * ``` + */ +class DefineSymbolExpr extends Expr, @define_symbol_expr { + /** Gets the name of the symbol. */ + string getName() { directive_define_symbols(this, result) } + + override string toString() { result = getName() } + + override string getAPrimaryQlClass() { result = "DefineSymbolExpr" } +} diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index ad723e09a4d..a13a6f6d628 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -332,7 +332,42 @@ using_directive_location( int loc: @location ref); @preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning - | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion; + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref); /* 0: false, 1: true */ + +directive_endifs( + unique int id: @directive_endif); + +#keyset[start, end] +directive_if_endif( + unique int start: @directive_if ref, + unique int end: @directive_endif ref); + +@directive_if_sibling = @directive_else | @directive_elif; + +#keyset[start, index] +directive_if_siblings( + int start: @directive_if ref, + int sibling: @directive_if_sibling ref, + int index: int ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); directive_regions( unique int id: @directive_region, @@ -955,7 +990,7 @@ expr_parent( int index: int ref, int parent: @control_flow_element ref); -@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; @top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; @@ -1104,6 +1139,8 @@ case @expr.kind of | 127 = @and_pattern_expr | 128 = @or_pattern_expr | 129 = @function_pointer_invocation_expr +/* Preprocessor */ +| 999 = @define_symbol_expr ; @switch = @switch_stmt | @switch_expr; diff --git a/csharp/ql/test/library-tests/comments/IfDirectives.expected b/csharp/ql/test/library-tests/comments/IfDirectives.expected new file mode 100644 index 00000000000..3a3a24ef798 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/IfDirectives.expected @@ -0,0 +1,19 @@ +ifDirectives +| trivia.cs:65:1:65:9 | #if ... | trivia.cs:76:1:76:6 | #endif | not taken | false | trivia.cs:65:5:65:9 | DEBUG | +| trivia.cs:68:1:68:10 | #if ... | trivia.cs:70:1:70:6 | #endif | not taken | false | trivia.cs:68:5:68:10 | NESTED | +siblings +| trivia.cs:65:1:65:9 | #if ... | trivia.cs:71:1:71:35 | #elif ... | 0 | taken | +| trivia.cs:65:1:65:9 | #if ... | trivia.cs:74:1:74:5 | #else | 1 | not taken | +conditionalDirectives +| trivia.cs:65:1:65:9 | #if ... | not taken | false | trivia.cs:65:5:65:9 | DEBUG | +| trivia.cs:68:1:68:10 | #if ... | not taken | false | trivia.cs:68:5:68:10 | NESTED | +| trivia.cs:71:1:71:35 | #elif ... | taken | true | trivia.cs:71:7:71:35 | ... \|\| ... | +expressions +| trivia.cs:65:5:65:9 | DEBUG | +| trivia.cs:68:5:68:10 | NESTED | +| trivia.cs:71:7:71:35 | ... \|\| ... | +| trivia.cs:71:8:71:15 | NOTDEBUG | +| trivia.cs:71:8:71:23 | ... == ... | +| trivia.cs:71:20:71:23 | true | +| trivia.cs:71:29:71:35 | !... | +| trivia.cs:71:31:71:34 | TEST | diff --git a/csharp/ql/test/library-tests/comments/IfDirectives.ql b/csharp/ql/test/library-tests/comments/IfDirectives.ql new file mode 100644 index 00000000000..d7e97d3abf8 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/IfDirectives.ql @@ -0,0 +1,33 @@ +import csharp + +private string getConditionValue(ConditionalDirective d) { + if d.conditionMatched() then result = "true" else result = "false" +} + +private string getBranchValue(BranchDirective d) { + if d.branchTaken() then result = "taken" else result = "not taken" +} + +query predicate ifDirectives( + IfDirective d, EndifDirective endif, string taken, string condValue, Expr expr +) { + d.getEndifDirective() = endif and + d.getCondition() = expr and + taken = getBranchValue(d) and + condValue = getConditionValue(d) +} + +query predicate siblings(IfDirective d, BranchDirective sibling, int index, string taken) { + d.getSiblingDirective(index) = sibling and + taken = getBranchValue(sibling) +} + +query predicate conditionalDirectives( + ConditionalDirective cond, string taken, string condValue, Expr expr +) { + cond.getCondition() = expr and + taken = getBranchValue(cond) and + condValue = getConditionValue(cond) +} + +query predicate expressions(Expr e) { e.getParent+() instanceof ConditionalDirective } diff --git a/csharp/ql/test/library-tests/comments/PrintAst.expected b/csharp/ql/test/library-tests/comments/PrintAst.expected new file mode 100644 index 00000000000..96f0f088501 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/PrintAst.expected @@ -0,0 +1,175 @@ +comments1.cs: +# 9| [Class] C +# 35| [Class] Foo +# 40| 5: [Field] x +# 40| -1: [TypeMention] int +# 43| 6: [Field] y +# 43| -1: [TypeMention] int +# 44| 7: [Field] z +# 44| -1: [TypeMention] int +comments2.cs: +# 11| [Class] C2 +# 13| 4: [Field] field1 +# 13| -1: [TypeMention] int +# 14| 5: [Field] field2 +# 14| -1: [TypeMention] int +# 19| 6: [Method] f +# 19| -1: [TypeMention] Void +# 20| 4: [BlockStmt] {...} +# 23| 0: [ExprStmt] ...; +# 23| 0: [MethodCall] call to method f +# 26| 1: [ExprStmt] ...; +# 26| 0: [MethodCall] call to method g +# 26| 0: [IntLiteral] 2 +# 29| 7: [Method] g +# 29| -1: [TypeMention] Void +#-----| 2: (Parameters) +# 29| 0: [Parameter] x +# 29| -1: [TypeMention] int +# 30| 4: [BlockStmt] {...} +# 32| 0: [LocalVariableDeclStmt] ... ...; +# 32| 0: [LocalVariableDeclAndInitExpr] Int32 y = ... +# 32| -1: [TypeMention] int +# 32| 0: [LocalVariableAccess] access to local variable y +# 32| 1: [IntLiteral] 0 +# 34| 1: [LocalVariableDeclStmt] ... ...; +# 34| 0: [LocalVariableDeclAndInitExpr] Int32 z = ... +# 34| -1: [TypeMention] int +# 34| 0: [LocalVariableAccess] access to local variable z +# 34| 1: [IntLiteral] 0 +# 40| 8: [Class] C3 +# 48| 9: [IndexerProperty] S1 +# 48| -1: [TypeMention] string +# 52| 3: [Getter] get_S1 +# 52| 4: [BlockStmt] {...} +# 52| 0: [ReturnStmt] return ...; +# 52| 0: [StringLiteral] "" +# 53| 4: [Setter] set_S1 +#-----| 2: (Parameters) +# 53| 0: [Parameter] value +# 54| 4: [BlockStmt] {...} +# 61| 10: [Enum] Values +# 66| 5: [Field] First +# 67| 6: [Field] Second +# 73| 7: [Field] Third +# 79| 11: [InstanceConstructor] C2 +# 80| 4: [BlockStmt] {...} +# 85| 12: [Destructor] ~C2 +# 86| 4: [BlockStmt] {...} +# 90| 13: [AddOperator] + +# 90| -1: [TypeMention] int +#-----| 2: (Parameters) +# 90| 0: [Parameter] x +# 90| -1: [TypeMention] C2 +# 90| 1: [Parameter] b +# 90| -1: [TypeMention] C2 +# 91| 4: [BlockStmt] {...} +# 92| 0: [ReturnStmt] return ...; +# 92| 0: [IntLiteral] 2 +# 95| 14: [Method] f +# 95| -1: [TypeMention] Void +#-----| 2: (Parameters) +# 96| 0: [Parameter] x +# 96| -1: [TypeMention] int +# 97| 1: [Parameter] y +# 97| -1: [TypeMention] int +# 99| 4: [BlockStmt] {...} +# 103| 15: [DelegateType] D +# 107| 16: [Event] E +# 107| -1: [TypeMention] D +# 107| 3: [AddEventAccessor] add_E +#-----| 2: (Parameters) +# 107| 0: [Parameter] value +# 107| 4: [RemoveEventAccessor] remove_E +#-----| 2: (Parameters) +# 107| 0: [Parameter] value +# 110| 17: [Method] gen +# 110| -1: [TypeMention] Void +# 111| 4: [BlockStmt] {...} +# 112| 0: [LocalVariableDeclStmt] ... ...; +# 112| 0: [LocalVariableDeclAndInitExpr] GenericClass t1 = ... +# 112| -1: [TypeMention] GenericClass +# 112| 0: [LocalVariableAccess] access to local variable t1 +# 112| 1: [ObjectCreation] object creation of type GenericClass +# 112| 0: [TypeMention] GenericClass +# 112| 1: [TypeMention] int +# 113| 1: [LocalVariableDeclStmt] ... ...; +# 113| 0: [LocalVariableDeclAndInitExpr] Int32 t2 = ... +# 113| -1: [TypeMention] int +# 113| 0: [LocalVariableAccess] access to local variable t2 +# 113| 1: [MethodCall] call to method GenericFn +# 114| 2: [LocalVariableDeclStmt] ... ...; +# 114| 0: [LocalVariableDeclAndInitExpr] GenericClass t3 = ... +# 114| -1: [TypeMention] GenericClass +# 114| 0: [LocalVariableAccess] access to local variable t3 +# 114| 1: [ObjectCreation] object creation of type GenericClass +# 114| 0: [TypeMention] GenericClass +# 114| 1: [TypeMention] double +# 115| 3: [LocalVariableDeclStmt] ... ...; +# 115| 0: [LocalVariableDeclAndInitExpr] Int32 t4 = ... +# 115| -1: [TypeMention] int +# 115| 0: [LocalVariableAccess] access to local variable t4 +# 115| 1: [MethodCall] call to method GenericFn +# 119| 18: [Class] GenericClass<> +#-----| 1: (Type parameters) +# 119| 0: [TypeParameter] T +# 121| 5: [Field] f +# 121| -1: [TypeMention] int +# 125| 21: [Method] GenericFn +# 125| -1: [TypeMention] int +#-----| 1: (Type parameters) +# 125| 0: [TypeParameter] T +# 126| 4: [BlockStmt] {...} +# 127| 0: [LocalVariableDeclStmt] ... ...; +# 127| 0: [LocalVariableDeclAndInitExpr] Int32 x = ... +# 127| -1: [TypeMention] int +# 127| 0: [LocalVariableAccess] access to local variable x +# 127| 1: [IntLiteral] 0 +# 128| 1: [ReturnStmt] return ...; +# 128| 0: [IntLiteral] 0 +trivia.cs: +# 14| [Class] Tr1 +# 16| 5: [Method] M1 +# 16| -1: [TypeMention] Void +# 17| 4: [BlockStmt] {...} +# 19| 0: [LocalVariableDeclStmt] ... ...; +# 19| 0: [LocalVariableDeclExpr] Int32 i +# 19| 0: [TypeMention] int +# 20| 1: [LocalVariableDeclStmt] ... ...; +# 20| 0: [LocalVariableDeclExpr] Int32 j +# 20| 0: [TypeMention] int +# 22| 2: [LocalVariableDeclStmt] ... ...; +# 22| 0: [LocalVariableDeclExpr] Char c +# 22| 0: [TypeMention] char +# 24| 3: [LocalVariableDeclStmt] ... ...; +# 24| 0: [LocalVariableDeclExpr] Single f +# 24| 0: [TypeMention] float +# 26| 4: [LocalVariableDeclStmt] ... ...; +# 26| 0: [LocalVariableDeclExpr] String s +# 26| 0: [TypeMention] string +# 28| 5: [LocalVariableDeclStmt] ... ...; +# 28| 0: [LocalVariableDeclExpr] Double d +# 28| 0: [TypeMention] double +# 32| [Class] Tr2 +# 34| 5: [Method] M1 +# 34| -1: [TypeMention] Void +# 35| 4: [BlockStmt] {...} +# 37| 0: [LocalVariableDeclStmt] ... ...; +# 37| 0: [LocalVariableDeclExpr] Int32 i +# 37| 0: [TypeMention] int +# 39| 1: [LocalVariableDeclStmt] ... ...; +# 39| 0: [LocalVariableDeclExpr] Int32 j +# 39| 0: [TypeMention] int +# 45| [Class] Tr3 +# 47| 5: [Method] M1 +# 47| -1: [TypeMention] Void +# 48| 4: [BlockStmt] {...} +# 61| [Class] Tr4 +# 63| 5: [Method] M1 +# 63| -1: [TypeMention] Void +# 64| 4: [BlockStmt] {...} +# 73| 0: [LocalVariableDeclStmt] ... ...; +# 73| 0: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 73| -1: [TypeMention] int +# 73| 0: [LocalVariableAccess] access to local variable i +# 73| 1: [IntLiteral] 1 diff --git a/csharp/ql/test/library-tests/comments/PrintAst.qlref b/csharp/ql/test/library-tests/comments/PrintAst.qlref new file mode 100644 index 00000000000..15af8b109dd --- /dev/null +++ b/csharp/ql/test/library-tests/comments/PrintAst.qlref @@ -0,0 +1 @@ +semmle/code/csharp/PrintAst.ql \ No newline at end of file From a896e1522d240aaadf827e53673ecacd7209bfc1 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 20 Jan 2021 15:42:27 +0100 Subject: [PATCH 119/429] Extract active flag from directives, fix missing assembly location --- .../PreprocessorDirective.cs | 1 + .../Semmle.Extraction.CSharp/Tuples.cs | 9 ++- .../src/semmle/code/csharp/Preprocessor.qll | 6 +- csharp/ql/src/semmlecode.csharp.dbscheme | 4 ++ .../comments/BindingAfter.expected | 2 +- .../library-tests/comments/Comments.expected | 2 +- .../comments/Directives.expected | 60 +++++++++++++++++++ .../test/library-tests/comments/Directives.ql | 6 ++ .../comments/ErrorDirectives.expected | 2 +- .../comments/WarningDirectives.expected | 2 +- .../ql/test/library-tests/comments/trivia.cs | 6 +- 11 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 csharp/ql/test/library-tests/comments/Directives.expected create mode 100644 csharp/ql/test/library-tests/comments/Directives.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs index e19ffe43549..2a968d7fa46 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -19,6 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities { PopulatePreprocessor(trapFile); + trapFile.preprocessor_directive_active(this, trivia.IsActive); trapFile.preprocessor_directive_location(this, cx.Create(ReportingLocation)); if (!cx.Extractor.Standalone) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 19b730f7cc0..46609d38bde 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -607,6 +607,13 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("preprocessor_directive_assembly", directive, assembly); } + internal static void preprocessor_directive_active(this TextWriter trapFile, + PreprocessorDirective directive, bool isActive) + where TDirective : DirectiveTriviaSyntax + { + trapFile.WriteTuple("preprocessor_directive_active", directive, isActive ? 1 : 0); + } + internal static void pragma_warnings(this TextWriter trapFile, PragmaWarningDirective pragma, int kind) { trapFile.WriteTuple("pragma_warnings", pragma, kind); @@ -706,7 +713,5 @@ namespace Semmle.Extraction.CSharp { trapFile.WriteTuple("directive_define_symbols", symb, name); } - - } } diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 1f23275a7a7..5b44fd3f30f 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -5,7 +5,11 @@ import Element class PreprocessorDirective extends Element, @preprocessor_directive { - override Location getALocation() { preprocessor_directive_location(this, result) } + predicate active() { preprocessor_directive_active(this, 1) } + + override Location getALocation() { + preprocessor_directive_location(this, result) or preprocessor_directive_assembly(this, result) + } } /** diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index a13a6f6d628..a904422305b 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -435,6 +435,10 @@ preprocessor_directive_assembly( unique int id: @preprocessor_directive ref, int loc: @assembly ref); +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + /** TYPES **/ types( diff --git a/csharp/ql/test/library-tests/comments/BindingAfter.expected b/csharp/ql/test/library-tests/comments/BindingAfter.expected index a44d0360f73..df5cd92ade0 100644 --- a/csharp/ql/test/library-tests/comments/BindingAfter.expected +++ b/csharp/ql/test/library-tests/comments/BindingAfter.expected @@ -55,6 +55,6 @@ | comments2.cs:118:5:118:21 | // ... | comments2.cs:119:11:119:25 | GenericClass<> | GenericClass<> | | comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:128:9:128:17 | return ...; | x | -| trivia.cs:1:1:3:15 | // ... | trivia.cs:14:7:14:9 | Tr1 | semmle-extractor-options: --standalone | +| trivia.cs:1:1:3:15 | // ... | trivia.cs:14:7:14:9 | Tr1 | | | trivia.cs:13:84:13:98 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | | trivia.cs:25:14:25:38 | // ... | trivia.cs:26:9:26:17 | ... ...; | numbering not affected | diff --git a/csharp/ql/test/library-tests/comments/Comments.expected b/csharp/ql/test/library-tests/comments/Comments.expected index 176211192a6..a6df0ef7bc6 100644 --- a/csharp/ql/test/library-tests/comments/Comments.expected +++ b/csharp/ql/test/library-tests/comments/Comments.expected @@ -70,7 +70,7 @@ singlelineComment | comments2.cs:124:5:124:16 | // ... | comments2.cs:124:5:124:16 | // ... | 1 | GenericFn | // GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:127:20:127:23 | // ... | 1 | x | // x | | comments2.cs:132:1:132:21 | // ... | comments2.cs:132:1:132:21 | // ... | 1 | End of comment2.cs | // End of comment2.cs | -| trivia.cs:1:1:3:15 | // ... | trivia.cs:1:1:1:42 | // ... | 3 | semmle-extractor-options: --standalone | // semmle-extractor-options: --standalone | +| trivia.cs:1:1:3:15 | // ... | trivia.cs:1:1:1:2 | // ... | 3 | | // | | trivia.cs:1:1:3:15 | // ... | trivia.cs:2:1:2:21 | // ... | 3 | Start of trivia.cs | // Start of trivia.cs | | trivia.cs:1:1:3:15 | // ... | trivia.cs:3:1:3:15 | // ... | 3 | Unassociated | // Unassociated | | trivia.cs:13:84:13:98 | // ... | trivia.cs:13:84:13:98 | // ... | 1 | New checksum | // New checksum | diff --git a/csharp/ql/test/library-tests/comments/Directives.expected b/csharp/ql/test/library-tests/comments/Directives.expected new file mode 100644 index 00000000000..2fa3a1acae3 --- /dev/null +++ b/csharp/ql/test/library-tests/comments/Directives.expected @@ -0,0 +1,60 @@ +| trivia.cs:4:1:4:13 | #define ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:4:1:4:13 | #define ... | trivia.cs:4:1:4:13 | trivia.cs:4:1:4:13 | active | +| trivia.cs:6:1:6:12 | #undef ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:6:1:6:12 | #undef ... | trivia.cs:6:1:6:12 | trivia.cs:6:1:6:12 | active | +| trivia.cs:12:1:12:35 | #pragma warning ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:12:1:12:35 | #pragma warning ... | trivia.cs:12:1:12:35 | trivia.cs:12:1:12:35 | active | +| trivia.cs:13:1:13:98 | #pragma checksum ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:13:1:13:98 | #pragma checksum ... | trivia.cs:13:1:13:98 | trivia.cs:13:1:13:98 | active | +| trivia.cs:18:1:18:19 | #line ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:18:1:18:19 | #line ... | trivia.cs:18:1:18:19 | trivia.cs:18:1:18:19 | active | +| trivia.cs:21:1:21:13 | #line default | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:21:1:21:13 | #line default | trivia.cs:21:1:21:13 | trivia.cs:21:1:21:13 | active | +| trivia.cs:23:1:23:23 | #pragma warning ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:23:1:23:23 | #pragma warning ... | trivia.cs:23:1:23:23 | trivia.cs:23:1:23:23 | active | +| trivia.cs:25:1:25:38 | #line hidden | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:25:1:25:38 | #line hidden | trivia.cs:25:1:25:38 | trivia.cs:25:1:25:38 | active | +| trivia.cs:27:1:27:9 | #line ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:27:1:27:9 | #line ... | trivia.cs:27:1:27:9 | trivia.cs:27:1:27:9 | active | +| trivia.cs:36:9:36:22 | #region ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:36:9:36:22 | #region ... | trivia.cs:36:9:36:22 | trivia.cs:36:9:36:22 | active | +| trivia.cs:38:9:38:22 | #region ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:38:9:38:22 | #region ... | trivia.cs:38:9:38:22 | trivia.cs:38:9:38:22 | active | +| trivia.cs:40:9:40:18 | #endregion | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:40:9:40:18 | #endregion | trivia.cs:40:9:40:18 | trivia.cs:40:9:40:18 | active | +| trivia.cs:41:9:41:18 | #endregion | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:41:9:41:18 | #endregion | trivia.cs:41:9:41:18 | trivia.cs:41:9:41:18 | active | +| trivia.cs:49:1:49:82 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:49:1:49:82 | #nullable ... | trivia.cs:49:1:49:82 | trivia.cs:49:1:49:82 | active | +| trivia.cs:50:1:50:80 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:50:1:50:80 | #nullable ... | trivia.cs:50:1:50:80 | trivia.cs:50:1:50:80 | active | +| trivia.cs:51:1:51:94 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:51:1:51:94 | #nullable ... | trivia.cs:51:1:51:94 | trivia.cs:51:1:51:94 | active | +| trivia.cs:52:1:52:81 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:52:1:52:81 | #nullable ... | trivia.cs:52:1:52:81 | trivia.cs:52:1:52:81 | active | +| trivia.cs:53:1:53:79 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:53:1:53:79 | #nullable ... | trivia.cs:53:1:53:79 | trivia.cs:53:1:53:79 | active | +| trivia.cs:54:1:54:93 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:54:1:54:93 | #nullable ... | trivia.cs:54:1:54:93 | trivia.cs:54:1:54:93 | active | +| trivia.cs:55:1:55:75 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:55:1:55:75 | #nullable ... | trivia.cs:55:1:55:75 | trivia.cs:55:1:55:75 | active | +| trivia.cs:56:1:56:73 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:56:1:56:73 | #nullable ... | trivia.cs:56:1:56:73 | trivia.cs:56:1:56:73 | active | +| trivia.cs:57:1:57:87 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:57:1:57:87 | #nullable ... | trivia.cs:57:1:57:87 | trivia.cs:57:1:57:87 | active | +| trivia.cs:65:1:65:9 | #if ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:65:1:65:9 | #if ... | trivia.cs:65:1:65:9 | trivia.cs:65:1:65:9 | active | +| trivia.cs:66:1:66:23 | #error ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | inactive | +| trivia.cs:66:1:66:23 | #error ... | trivia.cs:66:1:66:23 | trivia.cs:66:1:66:23 | inactive | +| trivia.cs:68:1:68:10 | #if ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | inactive | +| trivia.cs:68:1:68:10 | #if ... | trivia.cs:68:1:68:10 | trivia.cs:68:1:68:10 | inactive | +| trivia.cs:70:1:70:6 | #endif | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | inactive | +| trivia.cs:70:1:70:6 | #endif | trivia.cs:70:1:70:6 | trivia.cs:70:1:70:6 | inactive | +| trivia.cs:71:1:71:35 | #elif ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:71:1:71:35 | #elif ... | trivia.cs:71:1:71:35 | trivia.cs:71:1:71:35 | active | +| trivia.cs:72:1:72:43 | #warning ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:72:1:72:43 | #warning ... | trivia.cs:72:1:72:43 | trivia.cs:72:1:72:43 | active | +| trivia.cs:74:1:74:5 | #else | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:74:1:74:5 | #else | trivia.cs:74:1:74:5 | trivia.cs:74:1:74:5 | active | +| trivia.cs:76:1:76:6 | #endif | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +| trivia.cs:76:1:76:6 | #endif | trivia.cs:76:1:76:6 | trivia.cs:76:1:76:6 | active | diff --git a/csharp/ql/test/library-tests/comments/Directives.ql b/csharp/ql/test/library-tests/comments/Directives.ql new file mode 100644 index 00000000000..606ffd042bb --- /dev/null +++ b/csharp/ql/test/library-tests/comments/Directives.ql @@ -0,0 +1,6 @@ +import csharp + +query predicate directives(PreprocessorDirective d, Location l, string isActive) { + d.getALocation() = l and + if d.active() then isActive = "active" else isActive = "inactive" +} diff --git a/csharp/ql/test/library-tests/comments/ErrorDirectives.expected b/csharp/ql/test/library-tests/comments/ErrorDirectives.expected index 656b501c904..e3fb9babaf0 100644 --- a/csharp/ql/test/library-tests/comments/ErrorDirectives.expected +++ b/csharp/ql/test/library-tests/comments/ErrorDirectives.expected @@ -1 +1 @@ -| trivia.cs:72:1:72:41 | #error ... | NOTDEBUG is defined or TEST is not | +| trivia.cs:66:1:66:23 | #error ... | DEBUG is defined | diff --git a/csharp/ql/test/library-tests/comments/WarningDirectives.expected b/csharp/ql/test/library-tests/comments/WarningDirectives.expected index 105119a8127..b4ed32ea179 100644 --- a/csharp/ql/test/library-tests/comments/WarningDirectives.expected +++ b/csharp/ql/test/library-tests/comments/WarningDirectives.expected @@ -1 +1 @@ -| trivia.cs:66:1:66:25 | #warning ... | DEBUG is defined | +| trivia.cs:72:1:72:43 | #warning ... | NOTDEBUG is defined or TEST is not | diff --git a/csharp/ql/test/library-tests/comments/trivia.cs b/csharp/ql/test/library-tests/comments/trivia.cs index 69aea425499..61cfe454409 100644 --- a/csharp/ql/test/library-tests/comments/trivia.cs +++ b/csharp/ql/test/library-tests/comments/trivia.cs @@ -1,4 +1,4 @@ -// semmle-extractor-options: --standalone +// // Start of trivia.cs // Unassociated #define DEBUG @@ -63,13 +63,13 @@ class Tr4 static void M1() { #if DEBUG -#warning DEBUG is defined +#error DEBUG is defined var i = 0; #if NESTED i--; #endif #elif (NOTDEBUG == true) || !(TEST) -#error NOTDEBUG is defined or TEST is not +#warning NOTDEBUG is defined or TEST is not var i = 1; #else var i = 2; From 3900698b41571635cf9da85a2bda21d1c1cb852a Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 21 Jan 2021 11:28:23 +0100 Subject: [PATCH 120/429] Add doc comments for preprocessor directive base class --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 5b44fd3f30f..df33fc746e0 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -4,7 +4,17 @@ import Element +/** + * A preprocessor directive, such as `PragmaWarningDirective`, `PragmaChecksumDirective`, + * `DefineDirective`, `UndefineDirective`, `WarningDirective`, `ErrorDirective`, + * `NullableDirective`, `LineDirective`, `RegionDirective`, `EndRegionDirective`, + * `BranchDirective`, or `EndifDirective`. + */ class PreprocessorDirective extends Element, @preprocessor_directive { + /** + * Holds if this directive is processed by the preprocessor, such as any directive + * that is not inside a not taken `BranchDirective`. + */ predicate active() { preprocessor_directive_active(this, 1) } override Location getALocation() { From bd64dda4c393db0fafa2ec2271e242477ab7fe7b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 15:34:49 +0100 Subject: [PATCH 121/429] Fix code review findings in pragma warning directives --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 6 +++--- csharp/ql/test/library-tests/comments/PragmaWarnings.ql | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index df33fc746e0..b22058c05eb 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -27,13 +27,13 @@ class PreprocessorDirective extends Element, @preprocessor_directive { */ class PragmaWarningDirective extends PreprocessorDirective, @pragma_warning { /** Holds if this is a `#pragma warning restore` directive. */ - predicate restore() { pragma_warnings(this, 1) } + predicate isRestore() { pragma_warnings(this, 1) } /** Holds if this is a `#pragma warning disable` directive. */ - predicate disable() { pragma_warnings(this, 0) } + predicate isDisable() { pragma_warnings(this, 0) } /** Holds if this directive specifies error codes. */ - predicate hasErrorCodes() { exists(string s | pragma_warning_error_codes(this, s, _)) } + predicate hasErrorCodes() { pragma_warning_error_codes(this, _, _) } /** Gets a specified error code from this directive. */ string getAnErrorCode() { pragma_warning_error_codes(this, result, _) } diff --git a/csharp/ql/test/library-tests/comments/PragmaWarnings.ql b/csharp/ql/test/library-tests/comments/PragmaWarnings.ql index 15d793b6392..58ce589474e 100644 --- a/csharp/ql/test/library-tests/comments/PragmaWarnings.ql +++ b/csharp/ql/test/library-tests/comments/PragmaWarnings.ql @@ -1,8 +1,8 @@ import csharp -query predicate disable(PragmaWarningDirective pragma) { pragma.disable() } +query predicate disable(PragmaWarningDirective pragma) { pragma.isDisable() } -query predicate restore(PragmaWarningDirective pragma) { pragma.restore() } +query predicate restore(PragmaWarningDirective pragma) { pragma.isRestore() } query predicate errorCodes(PragmaWarningDirective pragma, string code) { pragma.hasErrorCodes() and code = pragma.getAnErrorCode() From 567516471c2a53d81503c64f1c2e1f0d938f006d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 15:37:05 +0100 Subject: [PATCH 122/429] Fix code review findings in 'define' directives --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index b22058c05eb..d747c870296 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -62,7 +62,7 @@ class PragmaChecksumDirective extends PreprocessorDirective, @pragma_checksum { } /** - * An `#define` directive. + * A `#define` directive. */ class DefineDirective extends PreprocessorDirective, @directive_define { /** Gets the name of the preprocessor symbol that is being set by this directive. */ From f7832adfb8762d99ff18de1091ed9a43ef433254 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 15:38:34 +0100 Subject: [PATCH 123/429] Fix code review findings in 'nullable' directives --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index d747c870296..416082596b1 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -114,13 +114,13 @@ class ErrorDirective extends PreprocessorDirective, @directive_error { */ class NullableDirective extends PreprocessorDirective, @directive_nullable { /** Holds if this is a `#nullable disable` directive. */ - predicate disable() { directive_nullables(this, 0, _) } + predicate isDisable() { directive_nullables(this, 0, _) } /** Holds if this is a `#nullable enable` directive. */ - predicate enable() { directive_nullables(this, 1, _) } + predicate isEnable() { directive_nullables(this, 1, _) } /** Holds if this is a `#nullable restore` directive. */ - predicate restore() { directive_nullables(this, 2, _) } + predicate isRestore() { directive_nullables(this, 2, _) } /** Holds if this directive targets all nullable contexts. */ predicate targetsAll() { directive_nullables(this, _, 0) } @@ -134,7 +134,7 @@ class NullableDirective extends PreprocessorDirective, @directive_nullable { /** Gets the succeeding `#nullable` directive in the file, if any. */ NullableDirective getSuccNullableDirective() { result = - rank[1](NullableDirective next | + min(NullableDirective next | next.getFile() = this.getFile() and next.getLocation().getStartLine() > this.getLocation().getStartLine() | From 6ef8e51bcfc6307bc75c3ca477538c7e63b2c206 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 15:58:25 +0100 Subject: [PATCH 124/429] Fix code review findings in 'line' directives --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 8 ++++---- .../test/library-tests/comments/LineDirectives.expected | 2 +- csharp/ql/test/library-tests/comments/LineDirectives.ql | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 416082596b1..e391fccbb6c 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -163,7 +163,7 @@ class LineDirective extends PreprocessorDirective, @directive_line { /** Gets the succeeding `#line` directive in the file, if any. */ LineDirective getSuccLineDirective() { result = - rank[1](LineDirective next | + min(LineDirective next | next.getFile() = this.getFile() and next.getLocation().getStartLine() > this.getLocation().getStartLine() | @@ -216,10 +216,10 @@ class NumericLineDirective extends LineDirective { int getLine() { directive_line_values(this, result, _) } /** Holds if this directive specifies a file name. */ - predicate hasFileName() { this.getFileName() != "" } + predicate hasFileName() { exists(this.getFileName()) } - /** Gets the file name of this directive. */ - string getFileName() { directive_line_values(this, _, result) } + /** Gets the file name of this directive, if any. */ + string getFileName() { directive_line_values(this, _, result) and result != "" } override string getAPrimaryQlClass() { result = "NumericLineDirective" } } diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.expected b/csharp/ql/test/library-tests/comments/LineDirectives.expected index ae79e53d1b4..c8be4e27890 100644 --- a/csharp/ql/test/library-tests/comments/LineDirectives.expected +++ b/csharp/ql/test/library-tests/comments/LineDirectives.expected @@ -4,7 +4,7 @@ hidden | trivia.cs:25:1:25:38 | #line hidden | lines | trivia.cs:18:1:18:19 | #line ... | 200 | Special | -| trivia.cs:27:1:27:9 | #line ... | 300 | | +| trivia.cs:27:1:27:9 | #line ... | 300 | no file | succ | trivia.cs:18:1:18:19 | #line ... | trivia.cs:21:1:21:13 | #line default | | trivia.cs:21:1:21:13 | #line default | trivia.cs:25:1:25:38 | #line hidden | diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.ql b/csharp/ql/test/library-tests/comments/LineDirectives.ql index db05488911a..4fa2adedb9d 100644 --- a/csharp/ql/test/library-tests/comments/LineDirectives.ql +++ b/csharp/ql/test/library-tests/comments/LineDirectives.ql @@ -5,7 +5,8 @@ query predicate default(DefaultLineDirective line) { any() } query predicate hidden(HiddenLineDirective line) { any() } query predicate lines(NumericLineDirective line, int l, string file) { - line.getLine() = l and line.getFileName() = file + line.getLine() = l and + if line.hasFileName() then line.getFileName() = file else file = "no file" } query predicate succ(LineDirective d, LineDirective succ) { d.getSuccLineDirective() = succ } From 60b23dc505e90c779c49477e589c99a867b864a6 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 16:03:43 +0100 Subject: [PATCH 125/429] Fix code review findings in 'endregion' directives --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 4 ++-- .../ql/test/library-tests/comments/RegionDirectives.expected | 4 ---- csharp/ql/test/library-tests/comments/RegionDirectives.ql | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index e391fccbb6c..090ee91b618 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -240,11 +240,11 @@ class RegionDirective extends PreprocessorDirective, @directive_region { } /** - * A `#endregion` directive. + * An `#endregion` directive. */ class EndRegionDirective extends PreprocessorDirective, @directive_endregion { /** Gets the opening `#region` directive. */ - RegionDirective getStart() { regions(result, this) } + RegionDirective getStart() { result.getEnd() = this } override string toString() { result = "#endregion" } diff --git a/csharp/ql/test/library-tests/comments/RegionDirectives.expected b/csharp/ql/test/library-tests/comments/RegionDirectives.expected index aead68e7ff0..9ede79514b6 100644 --- a/csharp/ql/test/library-tests/comments/RegionDirectives.expected +++ b/csharp/ql/test/library-tests/comments/RegionDirectives.expected @@ -1,6 +1,2 @@ -regionDirectives | trivia.cs:36:9:36:22 | #region ... | fields | trivia.cs:41:9:41:18 | #endregion | | trivia.cs:38:9:38:22 | #region ... | nested | trivia.cs:40:9:40:18 | #endregion | -endregions -| trivia.cs:40:9:40:18 | #endregion | trivia.cs:38:9:38:22 | #region ... | -| trivia.cs:41:9:41:18 | #endregion | trivia.cs:36:9:36:22 | #region ... | diff --git a/csharp/ql/test/library-tests/comments/RegionDirectives.ql b/csharp/ql/test/library-tests/comments/RegionDirectives.ql index 9b1296819f2..ea4c7cab4ec 100644 --- a/csharp/ql/test/library-tests/comments/RegionDirectives.ql +++ b/csharp/ql/test/library-tests/comments/RegionDirectives.ql @@ -4,5 +4,3 @@ query predicate regionDirectives(RegionDirective d, string name, EndRegionDirect d.getName() = name and d.getEnd() = end } - -query predicate endregions(EndRegionDirective d, RegionDirective start) { d.getStart() = start } From e450b614648d42b4c64d51591d8a2cc36e577f91 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 16:09:45 +0100 Subject: [PATCH 126/429] Fix code review findings in directives base class --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 2 +- csharp/ql/test/library-tests/comments/Directives.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 090ee91b618..11a2da1d4a5 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -15,7 +15,7 @@ class PreprocessorDirective extends Element, @preprocessor_directive { * Holds if this directive is processed by the preprocessor, such as any directive * that is not inside a not taken `BranchDirective`. */ - predicate active() { preprocessor_directive_active(this, 1) } + predicate isActive() { preprocessor_directive_active(this, 1) } override Location getALocation() { preprocessor_directive_location(this, result) or preprocessor_directive_assembly(this, result) diff --git a/csharp/ql/test/library-tests/comments/Directives.ql b/csharp/ql/test/library-tests/comments/Directives.ql index 606ffd042bb..3af699b9a0c 100644 --- a/csharp/ql/test/library-tests/comments/Directives.ql +++ b/csharp/ql/test/library-tests/comments/Directives.ql @@ -2,5 +2,5 @@ import csharp query predicate directives(PreprocessorDirective d, Location l, string isActive) { d.getALocation() = l and - if d.active() then isActive = "active" else isActive = "inactive" + if d.isActive() then isActive = "active" else isActive = "inactive" } From 2b7cc1575765bd69130ffb0ed0cbc5a11a20905f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 16:12:56 +0100 Subject: [PATCH 127/429] Introduce base class for branching and conditional directives --- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 4 ++-- csharp/ql/src/semmlecode.csharp.dbscheme | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 11a2da1d4a5..8ed13ce0426 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -255,7 +255,7 @@ class EndRegionDirective extends PreprocessorDirective, @directive_endregion { * A branching preprocessor directive, such as `IfDirective`, `ElifDirective`, or * `ElseDirective`. */ -class BranchDirective extends PreprocessorDirective { +class BranchDirective extends PreprocessorDirective, @branch_directive { /** Holds if the branch is taken by the preprocessor. */ predicate branchTaken() { none() } } @@ -264,7 +264,7 @@ class BranchDirective extends PreprocessorDirective { * A preprocessor directive with a branching condition, such as `IfDirective` or * `ElifDirective`. */ -class ConditionalDirective extends BranchDirective { +class ConditionalDirective extends BranchDirective, @conditional_directive { /** Gets the condition. */ Expr getCondition() { result = this.getChild(0) } diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index a904422305b..b85e3971657 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -335,6 +335,9 @@ using_directive_location( | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if | @directive_elif | @directive_else | @directive_endif; +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + directive_ifs( unique int id: @directive_if, int branchTaken: int ref, /* 0: false, 1: true */ From a5dec5b4aa754ea0e0bb72d7819ccd76d6fabcb6 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 16:32:05 +0100 Subject: [PATCH 128/429] C#: Limit ancestor traversal for 'if' and 'elif' lookup --- .../Entities/Expression.cs | 28 ++++++------------- .../Entities/Expressions/Literal.cs | 3 +- .../Entities/Expressions/Name.cs | 15 ++++++---- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 5829bbffa9e..6c738da3af1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -534,7 +534,7 @@ namespace Semmle.Extraction.CSharp.Entities return Expression.ValueAsString(c.Value); } - if (TryGetBoolValueInsideIfDirective(out var val)) + if (TryGetBoolValueFromLiteral(out var val)) { return Expression.ValueAsString(val); } @@ -604,30 +604,18 @@ namespace Semmle.Extraction.CSharp.Entities public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; - public bool IsInsideIfDirective() - { - return Node.Ancestors().Any(a => a is ElifDirectiveTriviaSyntax || a is IfDirectiveTriviaSyntax); - } - - public bool TryGetBoolValueInsideIfDirective(out bool val) + private bool TryGetBoolValueFromLiteral(out bool val) { var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression); var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression); - if (!isTrue && !isFalse) - { - val = false; - return false; - } - - if (!IsInsideIfDirective()) - { - val = false; - return false; - } - val = isTrue; - return true; + return isTrue || isFalse; + } + + public bool IsBoolLiteral() + { + return TryGetBoolValueFromLiteral(out var _); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs index d91f426cfd7..51acebef5c8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Literal.cs @@ -25,7 +25,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return ExprKind.NULL_LITERAL; } - if (info.TryGetBoolValueInsideIfDirective(out var _)) + // short circuit bool literals, because they have no type in `#if A = true` + if (info.IsBoolLiteral()) { return ExprKind.BOOL_LITERAL; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs index d74afd16329..faf5c9e2bd1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs @@ -27,15 +27,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (target == null) { - if (info.IsInsideIfDirective()) + if (IsInsideIfDirective(info.Node)) { return DefineSymbol.Create(info); } - else - { - info.Context.ModelError(info.Node, "Failed to resolve name"); - return new Unknown(info); - } + + info.Context.ModelError(info.Node, "Failed to resolve name"); + return new Unknown(info); } // There is a very strange bug in Microsoft.CodeAnalysis whereby @@ -72,5 +70,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions throw new InternalError(info.Node, $"Unhandled identifier kind '{target.Kind}'"); } } + + private static bool IsInsideIfDirective(ExpressionSyntax node) + { + return node.Ancestors().Any(a => a is ElifDirectiveTriviaSyntax || a is IfDirectiveTriviaSyntax); + } } } From 72547b89e60f4494f8c67a68e7b23b0275aa4ff7 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 26 Jan 2021 16:56:46 +0100 Subject: [PATCH 129/429] Rework endregion extraction --- .../PreprocessorDirectives/EndRegionDirective.cs | 15 +++++++-------- .../PreprocessorDirective.cs | 7 +++++-- .../Populators/DirectiveVisitor.cs | 4 ++-- .../extractor/Semmle.Extraction.CSharp/Tuples.cs | 4 ++-- csharp/ql/src/semmle/code/csharp/Preprocessor.qll | 2 +- csharp/ql/src/semmlecode.csharp.dbscheme | 9 +++------ 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs index a320c89028c..d4d75470a97 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndRegionDirective.cs @@ -5,19 +5,18 @@ namespace Semmle.Extraction.CSharp.Entities { internal class EndRegionDirective : PreprocessorDirective { - public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia) - : base(cx, trivia) + private readonly RegionDirective region; + + public EndRegionDirective(Context cx, EndRegionDirectiveTriviaSyntax trivia, RegionDirective region) + : base(cx, trivia, populateFromBase: false) { + this.region = region; + TryPopulate(); } protected override void PopulatePreprocessor(TextWriter trapFile) { - trapFile.directive_endregions(this); - } - - internal static void WriteRegionBlock(Context cx, RegionDirective region, EndRegionDirective endregion) - { - cx.TrapWriter.Writer.regions(region, endregion); + trapFile.directive_endregions(this, region); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs index 2a968d7fa46..62c70b3360e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -8,11 +8,14 @@ namespace Semmle.Extraction.CSharp.Entities { protected readonly TDirective trivia; - protected PreprocessorDirective(Context cx, TDirective trivia) + protected PreprocessorDirective(Context cx, TDirective trivia, bool populateFromBase = true) : base(cx) { this.trivia = trivia; - TryPopulate(); + if (populateFromBase) + { + TryPopulate(); + } } protected sealed override void Populate(TextWriter trapFile) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index 074441a70cb..f0044e891bc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -65,15 +65,15 @@ namespace Semmle.Extraction.CSharp.Populators public override void VisitEndRegionDirectiveTrivia(EndRegionDirectiveTriviaSyntax node) { - var endregion = new Entities.EndRegionDirective(cx, node); if (regionStarts.Count == 0) { cx.ExtractionError("Couldn't find start region", null, Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); return; } + var start = regionStarts.Pop(); - Entities.EndRegionDirective.WriteRegionBlock(cx, start, endregion); + new Entities.EndRegionDirective(cx, node, start); } private readonly Stack ifStarts = new Stack(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 46609d38bde..95f5db2d744 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -669,9 +669,9 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("directive_regions", directive, name); } - internal static void directive_endregions(this TextWriter trapFile, EndRegionDirective directive) + internal static void directive_endregions(this TextWriter trapFile, EndRegionDirective directive, RegionDirective start) { - trapFile.WriteTuple("directive_endregions", directive); + trapFile.WriteTuple("directive_endregions", directive, start); } internal static void regions(this TextWriter trapFile, RegionDirective start, EndRegionDirective end) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 8ed13ce0426..77c6bd199bb 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -232,7 +232,7 @@ class RegionDirective extends PreprocessorDirective, @directive_region { string getName() { directive_regions(this, result) } /** Gets the closing `#endregion` directive. */ - EndRegionDirective getEnd() { regions(this, result) } + EndRegionDirective getEnd() { directive_endregions(result, this) } override string toString() { result = "#region ..." } diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index b85e3971657..6dd5048ac60 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -376,13 +376,10 @@ directive_regions( unique int id: @directive_region, string name: string ref); +#keyset[id, start] directive_endregions( - unique int id: @directive_endregion); - -#keyset[start, end] -regions( - unique int start: @directive_region ref, - unique int end: @directive_endregion ref); + unique int id: @directive_endregion, + unique int start: @directive_region ref); directive_lines( unique int id: @directive_line, From 1ab4af275d1abc131af11b68ea54fc25b647028e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 27 Jan 2021 09:24:25 +0100 Subject: [PATCH 130/429] Rework if/elif/else/endif extraction --- .../PreprocessorDirectives/ElifDirective.cs | 12 ++++++-- .../PreprocessorDirectives/ElseDirective.cs | 12 ++++++-- .../PreprocessorDirectives/EndIfDirective.cs | 10 +++++-- .../PreprocessorDirectives/IfDirective.cs | 18 ------------ .../Populators/DirectiveVisitor.cs | 28 +++++++++++++------ .../Semmle.Extraction.CSharp/Tuples.cs | 24 ++++++---------- .../src/semmle/code/csharp/Preprocessor.qll | 22 +++++++++------ csharp/ql/src/semmlecode.csharp.dbscheme | 27 +++++++----------- 8 files changed, 76 insertions(+), 77 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs index 26314244ac6..ace89464b96 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs @@ -5,16 +5,22 @@ namespace Semmle.Extraction.CSharp.Entities { internal class ElifDirective : PreprocessorDirective, IIfSiblingDirective, IExpressionParentEntity { - public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia) - : base(cx, trivia) + private readonly IfDirective start; + private readonly int index; + + public ElifDirective(Context cx, ElifDirectiveTriviaSyntax trivia, IfDirective start, int index) + : base(cx, trivia, populateFromBase: false) { + this.start = start; + this.index = index; + TryPopulate(); } public bool IsTopLevelParent => true; protected override void PopulatePreprocessor(TextWriter trapFile) { - trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue); + trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue, start, index); Expression.Create(cx, trivia.Condition, this, 0); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs index 48c786627ac..7ab7d45b6e9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElseDirective.cs @@ -5,14 +5,20 @@ namespace Semmle.Extraction.CSharp.Entities { internal class ElseDirective : PreprocessorDirective, IIfSiblingDirective { - public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia) - : base(cx, trivia) + private readonly IfDirective start; + private readonly int index; + + public ElseDirective(Context cx, ElseDirectiveTriviaSyntax trivia, IfDirective start, int index) + : base(cx, trivia, populateFromBase: false) { + this.start = start; + this.index = index; + TryPopulate(); } protected override void PopulatePreprocessor(TextWriter trapFile) { - trapFile.directive_elses(this, trivia.BranchTaken); + trapFile.directive_elses(this, trivia.BranchTaken, start, index); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs index 85d5c89f353..9c349844dc6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/EndIfDirective.cs @@ -5,14 +5,18 @@ namespace Semmle.Extraction.CSharp.Entities { internal class EndIfDirective : PreprocessorDirective { - public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia) - : base(cx, trivia) + private readonly IfDirective start; + + public EndIfDirective(Context cx, EndIfDirectiveTriviaSyntax trivia, IfDirective start) + : base(cx, trivia, populateFromBase: false) { + this.start = start; + TryPopulate(); } protected override void PopulatePreprocessor(TextWriter trapFile) { - trapFile.directive_endifs(this); + trapFile.directive_endifs(this, start); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs index fc9af188c1d..e1b81e60d8a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs @@ -1,13 +1,10 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; -using System.Collections.Generic; using System.IO; namespace Semmle.Extraction.CSharp.Entities { internal class IfDirective : PreprocessorDirective, IExpressionParentEntity { - private readonly List branches = new List(); - public IfDirective(Context cx, IfDirectiveTriviaSyntax trivia) : base(cx, trivia) { @@ -21,20 +18,5 @@ namespace Semmle.Extraction.CSharp.Entities Expression.Create(cx, trivia.Condition, this, 0); } - - internal void Add(IIfSiblingDirective branch) - { - branches.Add(branch); - } - - internal void WriteBranches(EndIfDirective endif) - { - cx.TrapWriter.Writer.directive_if_endif(this, endif); - var siblings = 0; - foreach (var branch in branches) - { - cx.TrapWriter.Writer.directive_if_siblings(this, branch, siblings++); - } - } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index f0044e891bc..4098576a86d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -76,51 +76,63 @@ namespace Semmle.Extraction.CSharp.Populators new Entities.EndRegionDirective(cx, node, start); } - private readonly Stack ifStarts = new Stack(); + private class IfDirectiveStackElement + { + public Entities.IfDirective Entity { get; } + public int SiblingCount { get; set; } + + + public IfDirectiveStackElement(Entities.IfDirective entity) + { + Entity = entity; + } + } + + private readonly Stack ifStarts = new Stack(); public override void VisitIfDirectiveTrivia(IfDirectiveTriviaSyntax node) { var ifStart = new Entities.IfDirective(cx, node); - ifStarts.Push(ifStart); + ifStarts.Push(new IfDirectiveStackElement(ifStart)); } public override void VisitEndIfDirectiveTrivia(EndIfDirectiveTriviaSyntax node) { - var endif = new Entities.EndIfDirective(cx, node); if (ifStarts.Count == 0) { cx.ExtractionError("Couldn't find start if", null, Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); return; } + var start = ifStarts.Pop(); - start.WriteBranches(endif); + new Entities.EndIfDirective(cx, node, start.Entity); } public override void VisitElifDirectiveTrivia(ElifDirectiveTriviaSyntax node) { - var elif = new Entities.ElifDirective(cx, node); if (ifStarts.Count == 0) { cx.ExtractionError("Couldn't find start if", null, Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); return; } + var start = ifStarts.Peek(); - start.Add(elif); + new Entities.ElifDirective(cx, node, start.Entity, start.SiblingCount++); } public override void VisitElseDirectiveTrivia(ElseDirectiveTriviaSyntax node) { - var elseDirective = new Entities.ElseDirective(cx, node); if (ifStarts.Count == 0) { cx.ExtractionError("Couldn't find start if", null, Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); return; } + var start = ifStarts.Peek(); - start.Add(elseDirective); + new Entities.ElseDirective(cx, node, start.Entity, start.SiblingCount++); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 95f5db2d744..82416e64978 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -684,29 +684,21 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("directive_ifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0); } - internal static void directive_elifs(this TextWriter trapFile, ElifDirective directive, bool branchTaken, bool conditionValue) + internal static void directive_elifs(this TextWriter trapFile, ElifDirective directive, bool branchTaken, bool conditionValue, + IfDirective start, int index) { - trapFile.WriteTuple("directive_elifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0); + trapFile.WriteTuple("directive_elifs", directive, branchTaken ? 1 : 0, conditionValue ? 1 : 0, start, index); } - internal static void directive_elses(this TextWriter trapFile, ElseDirective directive, bool branchTaken) + internal static void directive_elses(this TextWriter trapFile, ElseDirective directive, bool branchTaken, + IfDirective start, int index) { - trapFile.WriteTuple("directive_elses", directive, branchTaken ? 1 : 0); + trapFile.WriteTuple("directive_elses", directive, branchTaken ? 1 : 0, start, index); } - internal static void directive_endifs(this TextWriter trapFile, EndIfDirective directive) + internal static void directive_endifs(this TextWriter trapFile, EndIfDirective directive, IfDirective start) { - trapFile.WriteTuple("directive_endifs", directive); - } - - internal static void directive_if_endif(this TextWriter trapFile, IfDirective start, EndIfDirective end) - { - trapFile.WriteTuple("directive_if_endif", start, end); - } - - internal static void directive_if_siblings(this TextWriter trapFile, IfDirective start, IIfSiblingDirective siblingDirective, int index) - { - trapFile.WriteTuple("directive_if_siblings", start, siblingDirective, index); + trapFile.WriteTuple("directive_endifs", directive, start); } internal static void directive_define_symbols(this TextWriter trapFile, DefineSymbol symb, string name) diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 77c6bd199bb..8548db264fd 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -281,10 +281,13 @@ class IfDirective extends ConditionalDirective, @directive_if { override predicate conditionMatched() { directive_ifs(this, _, 1) } /** Gets the closing `#endif` preprocessor directive. */ - EndifDirective getEndifDirective() { directive_if_endif(this, result) } + EndifDirective getEndifDirective() { directive_endifs(result, this) } /** Gets the sibling `#elif` or `#else` preprocessor directive at index `sibling`. */ - BranchDirective getSiblingDirective(int sibling) { directive_if_siblings(this, result, sibling) } + BranchDirective getSiblingDirective(int sibling) { + directive_elifs(result, _, _, this, sibling) or + directive_elses(result, _, this, sibling) + } /** Gets a sibling `#elif` or `#else` preprocessor directive. */ BranchDirective getASiblingDirective() { result = getSiblingDirective(_) } @@ -298,17 +301,18 @@ class IfDirective extends ConditionalDirective, @directive_if { * An `#elif` preprocessor directive. */ class ElifDirective extends ConditionalDirective, @directive_elif { - override predicate branchTaken() { directive_elifs(this, 1, _) } + override predicate branchTaken() { directive_elifs(this, 1, _, _, _) } - override predicate conditionMatched() { directive_elifs(this, _, 1) } + override predicate conditionMatched() { directive_elifs(this, _, 1, _, _) } /** Gets the opening `#if` preprocessor directive. */ - IfDirective getIfDirective() { directive_if_siblings(result, this, _) } + IfDirective getIfDirective() { directive_elifs(this, _, _, result, _) } /** Gets the successive branching preprocessor directive (`#elif` or `#else`), if any. */ BranchDirective getSuccSiblingDirective() { exists(IfDirective i, int index | - directive_if_siblings(i, this, index) and directive_if_siblings(i, result, index + 1) + this = i.getSiblingDirective(index) and + result = i.getSiblingDirective(index + 1) ) } @@ -322,9 +326,9 @@ class ElifDirective extends ConditionalDirective, @directive_elif { */ class ElseDirective extends BranchDirective, @directive_else { /** Gets the opening `#if` preprocessor directive. */ - IfDirective getIfDirective() { directive_if_siblings(result, this, _) } + IfDirective getIfDirective() { directive_elses(this, _, result, _) } - override predicate branchTaken() { directive_elses(this, 1) } + override predicate branchTaken() { directive_elses(this, 1, _, _) } override string toString() { result = "#else" } @@ -336,7 +340,7 @@ class ElseDirective extends BranchDirective, @directive_else { */ class EndifDirective extends PreprocessorDirective, @directive_endif { /** Gets the opening `#if` preprocessor directive. */ - IfDirective getIfDirective() { directive_if_endif(result, this) } + IfDirective getIfDirective() { directive_endifs(this, result) } override string toString() { result = "#endif" } diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 6dd5048ac60..f5d3daf62b8 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -346,28 +346,21 @@ directive_ifs( directive_elifs( unique int id: @directive_elif, int branchTaken: int ref, /* 0: false, 1: true */ - int conditionValue: int ref); /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); directive_elses( unique int id: @directive_else, - int branchTaken: int ref); /* 0: false, 1: true */ - -directive_endifs( - unique int id: @directive_endif); - -#keyset[start, end] -directive_if_endif( - unique int start: @directive_if ref, - unique int end: @directive_endif ref); - -@directive_if_sibling = @directive_else | @directive_elif; - -#keyset[start, index] -directive_if_siblings( - int start: @directive_if ref, - int sibling: @directive_if_sibling ref, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, int index: int ref); +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + directive_define_symbols( unique int id: @define_symbol_expr ref, string name: string ref); From 967765342ee1161140442c9ae378e88cb15abaf8 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 27 Jan 2021 16:17:32 +0100 Subject: [PATCH 131/429] Assign preprocessor directives to compilation + make compilation cached --- .../Semmle.Extraction.CSharp/Analyser.cs | 10 +- .../Entities/Compilation.cs | 125 ------------------ .../Entities/Compilations/Compilation.cs | 105 +++++++++++++++ .../Entities/Compilations/Diagnostic.cs | 23 ++++ .../Compilations/PerformanceMetrics.cs | 32 +++++ .../Entities/Compilations/Timings.cs | 11 ++ .../PreprocessorDirective.cs | 4 +- .../Semmle.Extraction.CSharp/Extractor.cs | 12 +- .../Semmle.Extraction.CSharp/Tuples.cs | 6 +- csharp/extractor/Semmle.Extraction/Context.cs | 12 +- .../src/semmle/code/csharp/Preprocessor.qll | 8 +- csharp/ql/src/semmlecode.csharp.dbscheme | 4 +- .../comments/Directives.expected | 62 ++++----- .../test/library-tests/comments/Directives.ql | 3 + 14 files changed, 236 insertions(+), 181 deletions(-) delete mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 5aa4f452d92..75db5c0e951 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -215,14 +215,12 @@ namespace Semmle.Extraction.CSharp /// /// Extracts compilation-wide entities, such as compilations and compiler diagnostics. /// - public void AnalyseCompilation(string cwd, string[] args) + public void AnalyseCompilation() { - extractionTasks.Add(() => DoAnalyseCompilation(cwd, args)); + extractionTasks.Add(() => DoAnalyseCompilation()); } - - - private void DoAnalyseCompilation(string cwd, string[] args) + private void DoAnalyseCompilation() { try { @@ -234,7 +232,7 @@ namespace Semmle.Extraction.CSharp compilationTrapFile = trapWriter; // Dispose later var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); - compilationEntity = new Entities.Compilation(cx, cwd, args); + compilationEntity = Entities.Compilation.Create(cx); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs deleted file mode 100644 index d4f0da99a28..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilation.cs +++ /dev/null @@ -1,125 +0,0 @@ -using Microsoft.CodeAnalysis; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Semmle.Util; - -namespace Semmle.Extraction.CSharp.Entities -{ - internal class Compilation : FreshEntity - { - private readonly string cwd; - private readonly string[] args; - - public Compilation(Context cx, string cwd, string[] args) : base(cx) - { - this.cwd = cwd; - this.args = args; - TryPopulate(); - } - - protected override void Populate(TextWriter trapFile) - { - var assembly = Extraction.Entities.Assembly.CreateOutputAssembly(cx); - - trapFile.compilations(this, FileUtils.ConvertToUnix(cwd)); - trapFile.compilation_assembly(this, assembly); - - // Arguments - var index = 0; - foreach (var arg in args) - { - trapFile.compilation_args(this, index++, arg); - } - - // Files - index = 0; - foreach (var file in cx.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(cx, tree.FilePath))) - { - trapFile.compilation_compiling_files(this, index++, file); - } - - // References - index = 0; - foreach (var file in cx.Compilation.References.OfType().Select(r => Extraction.Entities.File.Create(cx, r.FilePath))) - { - trapFile.compilation_referencing_files(this, index++, file); - } - - // Diagnostics - index = 0; - foreach (var diag in cx.Compilation.GetDiagnostics().Select(d => new Diagnostic(cx, d))) - { - trapFile.diagnostic_for(diag, this, 0, index++); - } - } - - public void PopulatePerformance(PerformanceMetrics p) - { - var trapFile = cx.TrapWriter.Writer; - var index = 0; - foreach (var metric in p.Metrics) - { - trapFile.compilation_time(this, -1, index++, metric); - } - trapFile.compilation_finished(this, (float)p.Total.Cpu.TotalSeconds, (float)p.Total.Elapsed.TotalSeconds); - } - - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - } - - internal class Diagnostic : FreshEntity - { - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - - private readonly Microsoft.CodeAnalysis.Diagnostic diagnostic; - - public Diagnostic(Context cx, Microsoft.CodeAnalysis.Diagnostic diag) : base(cx) - { - diagnostic = diag; - TryPopulate(); - } - - protected override void Populate(TextWriter trapFile) - { - trapFile.diagnostics(this, (int)diagnostic.Severity, diagnostic.Id, diagnostic.Descriptor.Title.ToString(), - diagnostic.GetMessage(), Extraction.Entities.Location.Create(cx, diagnostic.Location)); - } - } - - public struct Timings - { - public TimeSpan Elapsed { get; set; } - public TimeSpan Cpu { get; set; } - public TimeSpan User { get; set; } - } - - /// - /// The various performance metrics to log. - /// - public struct PerformanceMetrics - { - public Timings Frontend { get; set; } - public Timings Extractor { get; set; } - public Timings Total { get; set; } - public long PeakWorkingSet { get; set; } - - /// - /// These are in database order (0 indexed) - /// - public IEnumerable Metrics - { - get - { - yield return (float)Frontend.Cpu.TotalSeconds; - yield return (float)Frontend.Elapsed.TotalSeconds; - yield return (float)Extractor.Cpu.TotalSeconds; - yield return (float)Extractor.Elapsed.TotalSeconds; - yield return (float)Frontend.User.TotalSeconds; - yield return (float)Extractor.User.TotalSeconds; - yield return PeakWorkingSet / 1024.0f / 1024.0f; - } - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs new file mode 100644 index 00000000000..800e35d5ff4 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Compilation.cs @@ -0,0 +1,105 @@ +using Microsoft.CodeAnalysis; +using System; +using System.IO; +using System.Linq; +using Semmle.Util; + +namespace Semmle.Extraction.CSharp.Entities +{ + public class Compilation : CachedEntity + { + private static (string Cwd, string[] Args) settings; + private static int hashCode; + + public static (string Cwd, string[] Args) Settings + { + get { return settings; } + set + { + settings = value; + hashCode = settings.Cwd.GetHashCode(); + for (var i = 0; i < settings.Args.Length; i++) + { + hashCode = HashCode.Combine(hashCode, settings.Args[i].GetHashCode()); + } + } + } + + private Compilation(Context cx) : base(cx, null) + { + } + + public override void Populate(TextWriter trapFile) + { + var assembly = Extraction.Entities.Assembly.CreateOutputAssembly(Context); + + trapFile.compilations(this, FileUtils.ConvertToUnix(Compilation.Settings.Cwd)); + trapFile.compilation_assembly(this, assembly); + + // Arguments + var index = 0; + foreach (var arg in Compilation.Settings.Args) + { + trapFile.compilation_args(this, index++, arg); + } + + // Files + index = 0; + foreach (var file in Context.Compilation.SyntaxTrees.Select(tree => Extraction.Entities.File.Create(Context, tree.FilePath))) + { + trapFile.compilation_compiling_files(this, index++, file); + } + + // References + index = 0; + foreach (var file in Context.Compilation.References + .OfType() + .Select(r => Extraction.Entities.File.Create(Context, r.FilePath))) + { + trapFile.compilation_referencing_files(this, index++, file); + } + + // Diagnostics + index = 0; + foreach (var diag in Context.Compilation.GetDiagnostics().Select(d => new Diagnostic(Context, d))) + { + trapFile.diagnostic_for(diag, this, 0, index++); + } + } + + public void PopulatePerformance(PerformanceMetrics p) + { + var trapFile = Context.TrapWriter.Writer; + var index = 0; + foreach (var metric in p.Metrics) + { + trapFile.compilation_time(this, -1, index++, metric); + } + trapFile.compilation_finished(this, (float)p.Total.Cpu.TotalSeconds, (float)p.Total.Elapsed.TotalSeconds); + } + + public override void WriteId(TextWriter trapFile) + { + trapFile.Write(hashCode); + trapFile.Write(";compilation"); + } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public override Location ReportingLocation => throw new NotImplementedException(); + + public override bool NeedsPopulation => Context.IsAssemblyScope; + + private class CompilationFactory : ICachedEntityFactory + { + public static CompilationFactory Instance { get; } = new CompilationFactory(); + + public Compilation Create(Context cx, object init) => new Compilation(cx); + } + + private static readonly object compilationCacheKey = new object(); + + public static Compilation Create(Context cx) + => CompilationFactory.Instance.CreateEntity(cx, compilationCacheKey, null); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs new file mode 100644 index 00000000000..2900e5b0ae0 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs @@ -0,0 +1,23 @@ +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal class Diagnostic : FreshEntity + { + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + private readonly Microsoft.CodeAnalysis.Diagnostic diagnostic; + + public Diagnostic(Context cx, Microsoft.CodeAnalysis.Diagnostic diag) : base(cx) + { + diagnostic = diag; + TryPopulate(); + } + + protected override void Populate(TextWriter trapFile) + { + trapFile.diagnostics(this, (int)diagnostic.Severity, diagnostic.Id, diagnostic.Descriptor.Title.ToString(), + diagnostic.GetMessage(), Extraction.Entities.Location.Create(cx, diagnostic.Location)); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs new file mode 100644 index 00000000000..67aa2f25a88 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/PerformanceMetrics.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// The various performance metrics to log. + /// + public struct PerformanceMetrics + { + public Timings Frontend { get; set; } + public Timings Extractor { get; set; } + public Timings Total { get; set; } + public long PeakWorkingSet { get; set; } + + /// + /// These are in database order (0 indexed) + /// + public IEnumerable Metrics + { + get + { + yield return (float)Frontend.Cpu.TotalSeconds; + yield return (float)Frontend.Elapsed.TotalSeconds; + yield return (float)Extractor.Cpu.TotalSeconds; + yield return (float)Extractor.Elapsed.TotalSeconds; + yield return (float)Frontend.User.TotalSeconds; + yield return (float)Extractor.User.TotalSeconds; + yield return PeakWorkingSet / 1024.0f / 1024.0f; + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs new file mode 100644 index 00000000000..43f22922309 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Timings.cs @@ -0,0 +1,11 @@ +using System; + +namespace Semmle.Extraction.CSharp.Entities +{ + public struct Timings + { + public TimeSpan Elapsed { get; set; } + public TimeSpan Cpu { get; set; } + public TimeSpan User { get; set; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs index 62c70b3360e..6ea6172a2d3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -27,8 +27,8 @@ namespace Semmle.Extraction.CSharp.Entities if (!cx.Extractor.Standalone) { - var assembly = Assembly.CreateOutputAssembly(cx); - trapFile.preprocessor_directive_assembly(this, assembly); + var compilation = Compilation.Create(cx); + trapFile.preprocessor_directive_compilation(this, compilation); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs index cf991e0930a..2f979863dd0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Extractor.cs @@ -68,7 +68,10 @@ namespace Semmle.Extraction.CSharp { var stopwatch = new Stopwatch(); stopwatch.Start(); - var commandLineArguments = Options.CreateWithEnvironment(args); + + Entities.Compilation.Settings = (Directory.GetCurrentDirectory(), args); + + var commandLineArguments = Options.CreateWithEnvironment(Entities.Compilation.Settings.Args); var fileLogger = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath()); using var logger = commandLineArguments.Console ? new CombinedLogger(new ConsoleLogger(commandLineArguments.Verbosity), fileLogger) @@ -95,10 +98,9 @@ namespace Semmle.Extraction.CSharp return ExitCode.Ok; } - var cwd = Directory.GetCurrentDirectory(); var compilerArguments = CSharpCommandLineParser.Default.Parse( compilerVersion.ArgsWithResponse, - cwd, + Entities.Compilation.Settings.Cwd, compilerVersion.FrameworkPath, compilerVersion.AdditionalReferenceDirectories ); @@ -106,7 +108,7 @@ namespace Semmle.Extraction.CSharp if (compilerArguments == null) { var sb = new StringBuilder(); - sb.Append(" Failed to parse command line: ").AppendList(" ", args); + sb.Append(" Failed to parse command line: ").AppendList(" ", Entities.Compilation.Settings.Args); logger.Log(Severity.Error, sb.ToString()); ++analyser.CompilationErrors; return ExitCode.Failed; @@ -159,7 +161,7 @@ namespace Semmle.Extraction.CSharp ); analyser.EndInitialize(compilerArguments, commandLineArguments, compilation); - analyser.AnalyseCompilation(cwd, args); + analyser.AnalyseCompilation(); analyser.AnalyseReferences(); foreach (var tree in compilation.SyntaxTrees) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 82416e64978..0d88451c075 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -600,11 +600,11 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("preprocessor_directive_location", directive, location); } - internal static void preprocessor_directive_assembly(this TextWriter trapFile, - PreprocessorDirective directive, Assembly assembly) + internal static void preprocessor_directive_compilation(this TextWriter trapFile, + PreprocessorDirective directive, Compilation compilation) where TDirective : DirectiveTriviaSyntax { - trapFile.WriteTuple("preprocessor_directive_assembly", directive, assembly); + trapFile.WriteTuple("preprocessor_directive_compilation", directive, compilation); } internal static void preprocessor_directive_active(this TextWriter trapFile, diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index cbb68e1a936..a70a17ddaf2 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -246,7 +246,9 @@ namespace Semmle.Extraction public ICommentGenerator CommentGenerator { get; } = new CommentProcessor(); - private IExtractionScope scope { get; } + private IExtractionScope scope; + + public bool IsAssemblyScope => scope is AssemblyScope; public SyntaxTree? SourceTree => scope is SourceScope sc ? sc.SourceTree : null; @@ -368,9 +370,9 @@ namespace Semmle.Extraction throw new InternalError("Unexpected TrapStackBehaviour"); } - var a = duplicationGuard && this.Create(entity.ReportingLocation) is NonGeneratedSourceLocation loc ? - (Action)(() => WithDuplicationGuard(new Key(entity, loc), () => entity.Populate(TrapWriter.Writer))) : - (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer))); + var a = duplicationGuard && this.Create(entity.ReportingLocation) is NonGeneratedSourceLocation loc + ? (Action)(() => WithDuplicationGuard(new Key(entity, loc), () => entity.Populate(TrapWriter.Writer))) + : (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer))); if (deferred) populateQueue.Enqueue(a); @@ -384,7 +386,7 @@ namespace Semmle.Extraction /// public void WithDuplicationGuard(Key key, Action a) { - if (scope is AssemblyScope) + if (IsAssemblyScope) { // No need for a duplication guard when extracting assemblies, // and the duplication guard could lead to method bodies being missed diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 8548db264fd..776c136d672 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -3,6 +3,7 @@ */ import Element +private import semmle.code.csharp.commons.Compilation /** * A preprocessor directive, such as `PragmaWarningDirective`, `PragmaChecksumDirective`, @@ -17,9 +18,10 @@ class PreprocessorDirective extends Element, @preprocessor_directive { */ predicate isActive() { preprocessor_directive_active(this, 1) } - override Location getALocation() { - preprocessor_directive_location(this, result) or preprocessor_directive_assembly(this, result) - } + override Location getALocation() { preprocessor_directive_location(this, result) } + + /** Gets the compilation this directive belongs to, if any. */ + Compilation getCompilation() { preprocessor_directive_compilation(this, result) } } /** diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index f5d3daf62b8..fd73e34aa99 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -424,9 +424,9 @@ preprocessor_directive_location( unique int id: @preprocessor_directive ref, int loc: @location ref); -preprocessor_directive_assembly( +preprocessor_directive_compilation( unique int id: @preprocessor_directive ref, - int loc: @assembly ref); + int compilation: @compilation ref); preprocessor_directive_active( unique int id: @preprocessor_directive ref, diff --git a/csharp/ql/test/library-tests/comments/Directives.expected b/csharp/ql/test/library-tests/comments/Directives.expected index 2fa3a1acae3..191954695da 100644 --- a/csharp/ql/test/library-tests/comments/Directives.expected +++ b/csharp/ql/test/library-tests/comments/Directives.expected @@ -1,60 +1,62 @@ -| trivia.cs:4:1:4:13 | #define ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | +directives | trivia.cs:4:1:4:13 | #define ... | trivia.cs:4:1:4:13 | trivia.cs:4:1:4:13 | active | -| trivia.cs:6:1:6:12 | #undef ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:6:1:6:12 | #undef ... | trivia.cs:6:1:6:12 | trivia.cs:6:1:6:12 | active | -| trivia.cs:12:1:12:35 | #pragma warning ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:12:1:12:35 | #pragma warning ... | trivia.cs:12:1:12:35 | trivia.cs:12:1:12:35 | active | -| trivia.cs:13:1:13:98 | #pragma checksum ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:13:1:13:98 | #pragma checksum ... | trivia.cs:13:1:13:98 | trivia.cs:13:1:13:98 | active | -| trivia.cs:18:1:18:19 | #line ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:18:1:18:19 | #line ... | trivia.cs:18:1:18:19 | trivia.cs:18:1:18:19 | active | -| trivia.cs:21:1:21:13 | #line default | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:21:1:21:13 | #line default | trivia.cs:21:1:21:13 | trivia.cs:21:1:21:13 | active | -| trivia.cs:23:1:23:23 | #pragma warning ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:23:1:23:23 | #pragma warning ... | trivia.cs:23:1:23:23 | trivia.cs:23:1:23:23 | active | -| trivia.cs:25:1:25:38 | #line hidden | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:25:1:25:38 | #line hidden | trivia.cs:25:1:25:38 | trivia.cs:25:1:25:38 | active | -| trivia.cs:27:1:27:9 | #line ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:27:1:27:9 | #line ... | trivia.cs:27:1:27:9 | trivia.cs:27:1:27:9 | active | -| trivia.cs:36:9:36:22 | #region ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:36:9:36:22 | #region ... | trivia.cs:36:9:36:22 | trivia.cs:36:9:36:22 | active | -| trivia.cs:38:9:38:22 | #region ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:38:9:38:22 | #region ... | trivia.cs:38:9:38:22 | trivia.cs:38:9:38:22 | active | -| trivia.cs:40:9:40:18 | #endregion | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:40:9:40:18 | #endregion | trivia.cs:40:9:40:18 | trivia.cs:40:9:40:18 | active | -| trivia.cs:41:9:41:18 | #endregion | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:41:9:41:18 | #endregion | trivia.cs:41:9:41:18 | trivia.cs:41:9:41:18 | active | -| trivia.cs:49:1:49:82 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:49:1:49:82 | #nullable ... | trivia.cs:49:1:49:82 | trivia.cs:49:1:49:82 | active | -| trivia.cs:50:1:50:80 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:50:1:50:80 | #nullable ... | trivia.cs:50:1:50:80 | trivia.cs:50:1:50:80 | active | -| trivia.cs:51:1:51:94 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:51:1:51:94 | #nullable ... | trivia.cs:51:1:51:94 | trivia.cs:51:1:51:94 | active | -| trivia.cs:52:1:52:81 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:52:1:52:81 | #nullable ... | trivia.cs:52:1:52:81 | trivia.cs:52:1:52:81 | active | -| trivia.cs:53:1:53:79 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:53:1:53:79 | #nullable ... | trivia.cs:53:1:53:79 | trivia.cs:53:1:53:79 | active | -| trivia.cs:54:1:54:93 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:54:1:54:93 | #nullable ... | trivia.cs:54:1:54:93 | trivia.cs:54:1:54:93 | active | -| trivia.cs:55:1:55:75 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:55:1:55:75 | #nullable ... | trivia.cs:55:1:55:75 | trivia.cs:55:1:55:75 | active | -| trivia.cs:56:1:56:73 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:56:1:56:73 | #nullable ... | trivia.cs:56:1:56:73 | trivia.cs:56:1:56:73 | active | -| trivia.cs:57:1:57:87 | #nullable ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:57:1:57:87 | #nullable ... | trivia.cs:57:1:57:87 | trivia.cs:57:1:57:87 | active | -| trivia.cs:65:1:65:9 | #if ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:65:1:65:9 | #if ... | trivia.cs:65:1:65:9 | trivia.cs:65:1:65:9 | active | -| trivia.cs:66:1:66:23 | #error ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | inactive | | trivia.cs:66:1:66:23 | #error ... | trivia.cs:66:1:66:23 | trivia.cs:66:1:66:23 | inactive | -| trivia.cs:68:1:68:10 | #if ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | inactive | | trivia.cs:68:1:68:10 | #if ... | trivia.cs:68:1:68:10 | trivia.cs:68:1:68:10 | inactive | -| trivia.cs:70:1:70:6 | #endif | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | inactive | | trivia.cs:70:1:70:6 | #endif | trivia.cs:70:1:70:6 | trivia.cs:70:1:70:6 | inactive | -| trivia.cs:71:1:71:35 | #elif ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:71:1:71:35 | #elif ... | trivia.cs:71:1:71:35 | trivia.cs:71:1:71:35 | active | -| trivia.cs:72:1:72:43 | #warning ... | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:72:1:72:43 | #warning ... | trivia.cs:72:1:72:43 | trivia.cs:72:1:72:43 | active | -| trivia.cs:74:1:74:5 | #else | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:74:1:74:5 | #else | trivia.cs:74:1:74:5 | trivia.cs:74:1:74:5 | active | -| trivia.cs:76:1:76:6 | #endif | comments2.dll:0:0:0:0 | comments2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null | active | | trivia.cs:76:1:76:6 | #endif | trivia.cs:76:1:76:6 | trivia.cs:76:1:76:6 | active | +comp +| trivia.cs:4:1:4:13 | #define ... | compilation | +| trivia.cs:6:1:6:12 | #undef ... | compilation | +| trivia.cs:12:1:12:35 | #pragma warning ... | compilation | +| trivia.cs:13:1:13:98 | #pragma checksum ... | compilation | +| trivia.cs:18:1:18:19 | #line ... | compilation | +| trivia.cs:21:1:21:13 | #line default | compilation | +| trivia.cs:23:1:23:23 | #pragma warning ... | compilation | +| trivia.cs:25:1:25:38 | #line hidden | compilation | +| trivia.cs:27:1:27:9 | #line ... | compilation | +| trivia.cs:36:9:36:22 | #region ... | compilation | +| trivia.cs:38:9:38:22 | #region ... | compilation | +| trivia.cs:40:9:40:18 | #endregion | compilation | +| trivia.cs:41:9:41:18 | #endregion | compilation | +| trivia.cs:49:1:49:82 | #nullable ... | compilation | +| trivia.cs:50:1:50:80 | #nullable ... | compilation | +| trivia.cs:51:1:51:94 | #nullable ... | compilation | +| trivia.cs:52:1:52:81 | #nullable ... | compilation | +| trivia.cs:53:1:53:79 | #nullable ... | compilation | +| trivia.cs:54:1:54:93 | #nullable ... | compilation | +| trivia.cs:55:1:55:75 | #nullable ... | compilation | +| trivia.cs:56:1:56:73 | #nullable ... | compilation | +| trivia.cs:57:1:57:87 | #nullable ... | compilation | +| trivia.cs:65:1:65:9 | #if ... | compilation | +| trivia.cs:66:1:66:23 | #error ... | compilation | +| trivia.cs:68:1:68:10 | #if ... | compilation | +| trivia.cs:70:1:70:6 | #endif | compilation | +| trivia.cs:71:1:71:35 | #elif ... | compilation | +| trivia.cs:72:1:72:43 | #warning ... | compilation | +| trivia.cs:74:1:74:5 | #else | compilation | +| trivia.cs:76:1:76:6 | #endif | compilation | diff --git a/csharp/ql/test/library-tests/comments/Directives.ql b/csharp/ql/test/library-tests/comments/Directives.ql index 3af699b9a0c..4811692a9fc 100644 --- a/csharp/ql/test/library-tests/comments/Directives.ql +++ b/csharp/ql/test/library-tests/comments/Directives.ql @@ -1,6 +1,9 @@ import csharp +private import semmle.code.csharp.commons.Compilation query predicate directives(PreprocessorDirective d, Location l, string isActive) { d.getALocation() = l and if d.isActive() then isActive = "active" else isActive = "inactive" } + +query predicate comp(PreprocessorDirective d, Compilation c) { d.getCompilation() = c } From a1d227dbbbecc23b33d9f77b3caf19120322c97e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 22 Jan 2021 14:51:32 +0100 Subject: [PATCH 132/429] C#: Follow line directives when getting element location --- .../PreprocessorDirectives/LineDirective.cs | 8 +++- .../PragmaChecksumDirective.cs | 3 +- .../Semmle.Extraction.CSharp/Tuples.cs | 11 +++-- csharp/extractor/Semmle.Extraction/Context.cs | 6 --- .../Semmle.Extraction/Entities/File.cs | 40 ++++++++++++++++--- .../Entities/SourceLocation.cs | 13 +++++- csharp/extractor/Semmle.Extraction/Tuples.cs | 5 +++ .../semmle/code/csharp/ExprOrStmtParent.qll | 9 ++++- csharp/ql/src/semmle/code/csharp/Location.qll | 3 ++ .../src/semmle/code/csharp/Preprocessor.qll | 11 ++--- csharp/ql/src/semmlecode.csharp.dbscheme | 16 ++++++-- .../comments/BindingAfter.expected | 2 +- .../library-tests/comments/Bindings.expected | 2 +- .../library-tests/comments/Comments.expected | 2 +- .../comments/Directives.expected | 12 +++--- .../comments/LineDirectives.expected | 21 +++++++--- .../library-tests/comments/LineDirectives.ql | 11 +++-- .../comments/PragmaChecksums.expected | 2 +- .../library-tests/comments/PragmaChecksums.ql | 2 +- .../library-tests/comments/PrintAst.expected | 12 ++++-- .../ql/test/library-tests/comments/trivia.cs | 6 +-- 21 files changed, 139 insertions(+), 58 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs index 2ca34d6c7a1..54681d317e9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs @@ -27,7 +27,13 @@ namespace Semmle.Extraction.CSharp.Entities if (trivia.Line.IsKind(SyntaxKind.NumericLiteralToken)) { var value = (int)trivia.Line.Value; - trapFile.directive_line_values(this, value, trivia.File.ValueText); + trapFile.directive_line_value(this, value); + + if (!string.IsNullOrWhiteSpace(trivia.File.ValueText)) + { + var file = Extraction.Entities.File.Create(cx, trivia.File.ValueText); + trapFile.directive_line_file(this, file); + } } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs index 9de67176e54..dff901fa826 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs @@ -12,7 +12,8 @@ namespace Semmle.Extraction.CSharp.Entities protected override void PopulatePreprocessor(TextWriter trapFile) { - trapFile.pragma_checksums(this, trivia.File.ToString(), trivia.Guid.ToString(), trivia.Bytes.ToString()); + var file = Extraction.Entities.File.Create(cx, trivia.File.ValueText); + trapFile.pragma_checksums(this, file, trivia.Guid.ToString(), trivia.Bytes.ToString()); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 0d88451c075..ec2bd66d32e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -624,7 +624,7 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("pragma_warning_error_codes", pragma, errorCode, child); } - internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, string file, string guid, string bytes) + internal static void pragma_checksums(this TextWriter trapFile, PragmaChecksumDirective pragma, Extraction.Entities.File file, string guid, string bytes) { trapFile.WriteTuple("pragma_checksums", pragma, file, guid, bytes); } @@ -659,9 +659,14 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("directive_lines", directive, kind); } - internal static void directive_line_values(this TextWriter trapFile, LineDirective directive, int line, string file) + internal static void directive_line_value(this TextWriter trapFile, LineDirective directive, int line) { - trapFile.WriteTuple("directive_line_values", directive, line, file); + trapFile.WriteTuple("directive_line_value", directive, line); + } + + internal static void directive_line_file(this TextWriter trapFile, LineDirective directive, Extraction.Entities.File file) + { + trapFile.WriteTuple("directive_line_file", directive, file); } internal static void directive_regions(this TextWriter trapFile, RegionDirective directive, string name) diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index a70a17ddaf2..10a24990a13 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -262,12 +262,6 @@ namespace Semmle.Extraction !SymbolEqualityComparer.Default.Equals(symbol, symbol.OriginalDefinition) || scope.InScope(symbol); - /// - /// Whether the current extraction context defines a given file. - /// - /// The path to query. - public bool DefinesFile(string path) => scope.InFileScope(path); - private int currentRecursiveDepth = 0; private const int maxRecursiveDepth = 150; diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs index 80bc3ad0533..72d0ea8e986 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/File.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.Entities private readonly Lazy transformedPathLazy; private PathTransformer.ITransformedPath TransformedPath => transformedPathLazy.Value; - public override bool NeedsPopulation => Context.DefinesFile(originalPath) || originalPath == Context.Extractor.OutputPath; + public override bool NeedsPopulation => true; public override void Populate(TextWriter trapFile) { @@ -27,12 +27,11 @@ namespace Semmle.Extraction.Entities if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir) trapFile.containerparent(Folder.Create(Context, dir), this); - var fromSource = TransformedPath.Extension.ToLowerInvariant().Equals("cs"); - if (fromSource) + var trees = Context.Compilation.SyntaxTrees.Where(t => t.FilePath == originalPath); + + if (trees.Any()) { - foreach (var text in Context.Compilation.SyntaxTrees - .Where(t => t.FilePath == originalPath) - .Select(tree => tree.GetText())) + foreach (var text in trees.Select(tree => tree.GetText())) { var rawText = text.ToString() ?? ""; var lineCounts = LineCounter.ComputeLineCounts(rawText); @@ -43,10 +42,39 @@ namespace Semmle.Extraction.Entities Context.TrapWriter.Archive(originalPath, TransformedPath, text.Encoding ?? System.Text.Encoding.Default); } } + else if (IsPossiblyTextFile()) + { + try + { + System.Text.Encoding encoding; + var lineCount = 0; + using (var sr = new StreamReader(originalPath, detectEncodingFromByteOrderMarks: true)) + { + while (sr.ReadLine() != null) + { + lineCount++; + } + encoding = sr.CurrentEncoding; + } + + trapFile.numlines(this, new LineCounts() { Total = lineCount, Code = 0, Comment = 0 }); + Context.TrapWriter.Archive(originalPath, TransformedPath, encoding ?? System.Text.Encoding.Default); + } + catch (Exception exc) + { + Context.ExtractionError($"Couldn't read file", originalPath, null, exc.StackTrace); + } + } trapFile.file_extraction_mode(this, Context.Extractor.Standalone ? 1 : 0); } + private bool IsPossiblyTextFile() + { + var extension = TransformedPath.Extension.ToLowerInvariant(); + return !extension.Equals("dll") && !extension.Equals("exe"); + } + public override void WriteId(System.IO.TextWriter trapFile) { trapFile.Write(TransformedPath.DatabaseId); diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs index 2697049dce2..41688033f04 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs @@ -28,8 +28,17 @@ namespace Semmle.Extraction.Entities public override void Populate(TextWriter trapFile) { - trapFile.locations_default(this, FileEntity, Position.Span.Start.Line + 1, Position.Span.Start.Character + 1, - Position.Span.End.Line + 1, Position.Span.End.Character); + trapFile.locations_default(this, FileEntity, + Position.Span.Start.Line + 1, Position.Span.Start.Character + 1, + Position.Span.End.Line + 1, Position.Span.End.Character); + + var mapped = symbol.GetMappedLineSpan(); + if (mapped.HasMappedPath && mapped.IsValid) + { + var mappedLoc = Create(Context, Microsoft.CodeAnalysis.Location.Create(mapped.Path, default, mapped.Span)); + + trapFile.locations_mapped(this, mappedLoc); + } } public FileLinePositionSpan Position diff --git a/csharp/extractor/Semmle.Extraction/Tuples.cs b/csharp/extractor/Semmle.Extraction/Tuples.cs index 0a71ba6b3d9..8e9016cb6b6 100644 --- a/csharp/extractor/Semmle.Extraction/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction/Tuples.cs @@ -43,6 +43,11 @@ namespace Semmle.Extraction trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol); } + public static void locations_mapped(this System.IO.TextWriter trapFile, SourceLocation l1, Location l2) + { + trapFile.WriteTuple("locations_mapped", l1, l2); + } + public static void numlines(this System.IO.TextWriter trapFile, IEntity label, LineCounts lineCounts) { trapFile.WriteTuple("numlines", label, lineCounts.Total, lineCounts.Code, lineCounts.Comment); diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll index 80029612a7c..5d140b17968 100644 --- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll @@ -57,7 +57,14 @@ cached private module Cached { cached Location bestLocation(Element e) { - result = e.getALocation().(SourceLocation) + result = e.getALocation().(SourceLocation) and + ( + not exists(e.getALocation().(SourceLocation).getMappedLocation()) or + e instanceof LineDirective + ) + or + result = e.getALocation().(SourceLocation).getMappedLocation() and + not e instanceof LineDirective or hasNoSourceLocation(e) and result = min(Location l | l = e.getALocation() | l order by l.getFile().toString()) diff --git a/csharp/ql/src/semmle/code/csharp/Location.qll b/csharp/ql/src/semmle/code/csharp/Location.qll index ac9a120849c..5d35933f246 100644 --- a/csharp/ql/src/semmle/code/csharp/Location.qll +++ b/csharp/ql/src/semmle/code/csharp/Location.qll @@ -62,6 +62,9 @@ class EmptyLocation extends Location { * within the file. */ class SourceLocation extends Location, @location_default { + /** Gets the location that takes into account `#line` directives, if any. */ + Location getMappedLocation() { locations_mapped(this, result) } + override File getFile() { locations_default(this, result, _, _, _, _) } override predicate hasLocationInfo( diff --git a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll index 776c136d672..daf4978da53 100644 --- a/csharp/ql/src/semmle/code/csharp/Preprocessor.qll +++ b/csharp/ql/src/semmle/code/csharp/Preprocessor.qll @@ -50,7 +50,7 @@ class PragmaWarningDirective extends PreprocessorDirective, @pragma_warning { */ class PragmaChecksumDirective extends PreprocessorDirective, @pragma_checksum { /** Gets the file name of this directive. */ - string getFileName() { pragma_checksums(this, result, _, _) } + File getReferencedFile() { pragma_checksums(this, result, _, _) } /** Gets the GUID of this directive. */ string getGuid() { pragma_checksums(this, _, result, _) } @@ -215,13 +215,10 @@ class NumericLineDirective extends LineDirective { NumericLineDirective() { directive_lines(this, 2) } /** Gets the line number of this directive. */ - int getLine() { directive_line_values(this, result, _) } + int getLine() { directive_line_value(this, result) } - /** Holds if this directive specifies a file name. */ - predicate hasFileName() { exists(this.getFileName()) } - - /** Gets the file name of this directive, if any. */ - string getFileName() { directive_line_values(this, _, result) and result != "" } + /** Gets the referenced file of this directive. */ + File getReferencedFile() { directive_line_file(this, result) } override string getAPrimaryQlClass() { result = "NumericLineDirective" } } diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index fd73e34aa99..68db341c2ed 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -247,6 +247,10 @@ locations_default( int endLine: int ref, int endColumn: int ref); +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + @sourceline = @file | @callable | @xmllocatable; numlines( @@ -378,10 +382,14 @@ directive_lines( unique int id: @directive_line, int kind: int ref); /* 0: default, 1: hidden, 2: numeric */ -directive_line_values( +directive_line_value( unique int id: @directive_line ref, - int line: int ref, - string file: string ref); + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref +) directive_nullables( unique int id: @directive_nullable, @@ -406,7 +414,7 @@ directive_defines( pragma_checksums( unique int id: @pragma_checksum, - string file: string ref, + int file: @file ref, string guid: string ref, string bytes: string ref); diff --git a/csharp/ql/test/library-tests/comments/BindingAfter.expected b/csharp/ql/test/library-tests/comments/BindingAfter.expected index df5cd92ade0..59b784aa196 100644 --- a/csharp/ql/test/library-tests/comments/BindingAfter.expected +++ b/csharp/ql/test/library-tests/comments/BindingAfter.expected @@ -56,5 +56,5 @@ | comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:128:9:128:17 | return ...; | x | | trivia.cs:1:1:3:15 | // ... | trivia.cs:14:7:14:9 | Tr1 | | -| trivia.cs:13:84:13:98 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | +| trivia.cs:13:89:13:103 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | | trivia.cs:25:14:25:38 | // ... | trivia.cs:26:9:26:17 | ... ...; | numbering not affected | diff --git a/csharp/ql/test/library-tests/comments/Bindings.expected b/csharp/ql/test/library-tests/comments/Bindings.expected index 90889ddeda0..6822c9411a6 100644 --- a/csharp/ql/test/library-tests/comments/Bindings.expected +++ b/csharp/ql/test/library-tests/comments/Bindings.expected @@ -49,7 +49,7 @@ | comments2.cs:121:17:121:20 | // ... | comments2.cs:121:13:121:13 | f | f | | comments2.cs:124:5:124:16 | // ... | comments2.cs:125:9:125:20 | GenericFn | GenericFn | | comments2.cs:127:20:127:23 | // ... | comments2.cs:127:9:127:18 | ... ...; | x | -| trivia.cs:13:84:13:98 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | +| trivia.cs:13:89:13:103 | // ... | trivia.cs:14:7:14:9 | Tr1 | New checksum | | trivia.cs:25:14:25:38 | // ... | trivia.cs:17:5:29:5 | {...} | numbering not affected | | trivia.cs:49:18:49:82 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation and warning contexts to disabled. | | trivia.cs:50:17:50:80 | // ... | trivia.cs:48:5:58:5 | {...} | Sets the nullable annotation and warning contexts to enabled. | diff --git a/csharp/ql/test/library-tests/comments/Comments.expected b/csharp/ql/test/library-tests/comments/Comments.expected index a6df0ef7bc6..a0ff83a59be 100644 --- a/csharp/ql/test/library-tests/comments/Comments.expected +++ b/csharp/ql/test/library-tests/comments/Comments.expected @@ -73,7 +73,7 @@ singlelineComment | trivia.cs:1:1:3:15 | // ... | trivia.cs:1:1:1:2 | // ... | 3 | | // | | trivia.cs:1:1:3:15 | // ... | trivia.cs:2:1:2:21 | // ... | 3 | Start of trivia.cs | // Start of trivia.cs | | trivia.cs:1:1:3:15 | // ... | trivia.cs:3:1:3:15 | // ... | 3 | Unassociated | // Unassociated | -| trivia.cs:13:84:13:98 | // ... | trivia.cs:13:84:13:98 | // ... | 1 | New checksum | // New checksum | +| trivia.cs:13:89:13:103 | // ... | trivia.cs:13:89:13:103 | // ... | 1 | New checksum | // New checksum | | trivia.cs:25:14:25:38 | // ... | trivia.cs:25:14:25:38 | // ... | 1 | numbering not affected | // numbering not affected | | trivia.cs:49:18:49:82 | // ... | trivia.cs:49:18:49:82 | // ... | 1 | Sets the nullable annotation and warning contexts to disabled. | // Sets the nullable annotation and warning contexts to disabled. | | trivia.cs:50:17:50:80 | // ... | trivia.cs:50:17:50:80 | // ... | 1 | Sets the nullable annotation and warning contexts to enabled. | // Sets the nullable annotation and warning contexts to enabled. | diff --git a/csharp/ql/test/library-tests/comments/Directives.expected b/csharp/ql/test/library-tests/comments/Directives.expected index 191954695da..c6d0a12ffb6 100644 --- a/csharp/ql/test/library-tests/comments/Directives.expected +++ b/csharp/ql/test/library-tests/comments/Directives.expected @@ -2,12 +2,12 @@ directives | trivia.cs:4:1:4:13 | #define ... | trivia.cs:4:1:4:13 | trivia.cs:4:1:4:13 | active | | trivia.cs:6:1:6:12 | #undef ... | trivia.cs:6:1:6:12 | trivia.cs:6:1:6:12 | active | | trivia.cs:12:1:12:35 | #pragma warning ... | trivia.cs:12:1:12:35 | trivia.cs:12:1:12:35 | active | -| trivia.cs:13:1:13:98 | #pragma checksum ... | trivia.cs:13:1:13:98 | trivia.cs:13:1:13:98 | active | -| trivia.cs:18:1:18:19 | #line ... | trivia.cs:18:1:18:19 | trivia.cs:18:1:18:19 | active | +| trivia.cs:13:1:13:103 | #pragma checksum ... | trivia.cs:13:1:13:103 | trivia.cs:13:1:13:103 | active | +| trivia.cs:18:1:18:22 | #line ... | trivia.cs:18:1:18:22 | trivia.cs:18:1:18:22 | active | | trivia.cs:21:1:21:13 | #line default | trivia.cs:21:1:21:13 | trivia.cs:21:1:21:13 | active | | trivia.cs:23:1:23:23 | #pragma warning ... | trivia.cs:23:1:23:23 | trivia.cs:23:1:23:23 | active | | trivia.cs:25:1:25:38 | #line hidden | trivia.cs:25:1:25:38 | trivia.cs:25:1:25:38 | active | -| trivia.cs:27:1:27:9 | #line ... | trivia.cs:27:1:27:9 | trivia.cs:27:1:27:9 | active | +| trivia.cs:27:1:27:7 | #line ... | trivia.cs:27:1:27:7 | trivia.cs:27:1:27:7 | active | | trivia.cs:36:9:36:22 | #region ... | trivia.cs:36:9:36:22 | trivia.cs:36:9:36:22 | active | | trivia.cs:38:9:38:22 | #region ... | trivia.cs:38:9:38:22 | trivia.cs:38:9:38:22 | active | | trivia.cs:40:9:40:18 | #endregion | trivia.cs:40:9:40:18 | trivia.cs:40:9:40:18 | active | @@ -33,12 +33,12 @@ comp | trivia.cs:4:1:4:13 | #define ... | compilation | | trivia.cs:6:1:6:12 | #undef ... | compilation | | trivia.cs:12:1:12:35 | #pragma warning ... | compilation | -| trivia.cs:13:1:13:98 | #pragma checksum ... | compilation | -| trivia.cs:18:1:18:19 | #line ... | compilation | +| trivia.cs:13:1:13:103 | #pragma checksum ... | compilation | +| trivia.cs:18:1:18:22 | #line ... | compilation | | trivia.cs:21:1:21:13 | #line default | compilation | | trivia.cs:23:1:23:23 | #pragma warning ... | compilation | | trivia.cs:25:1:25:38 | #line hidden | compilation | -| trivia.cs:27:1:27:9 | #line ... | compilation | +| trivia.cs:27:1:27:7 | #line ... | compilation | | trivia.cs:36:9:36:22 | #region ... | compilation | | trivia.cs:38:9:38:22 | #region ... | compilation | | trivia.cs:40:9:40:18 | #endregion | compilation | diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.expected b/csharp/ql/test/library-tests/comments/LineDirectives.expected index c8be4e27890..58b54de85e6 100644 --- a/csharp/ql/test/library-tests/comments/LineDirectives.expected +++ b/csharp/ql/test/library-tests/comments/LineDirectives.expected @@ -2,12 +2,21 @@ default | trivia.cs:21:1:21:13 | #line default | hidden | trivia.cs:25:1:25:38 | #line hidden | -lines -| trivia.cs:18:1:18:19 | #line ... | 200 | Special | -| trivia.cs:27:1:27:9 | #line ... | 300 | no file | +lines_file +| trivia.cs:18:1:18:22 | #line ... | 1 | comments1.cs:0:0:0:0 | comments1.cs | +lines_no_file +| trivia.cs:27:1:27:7 | #line ... | 5 | succ -| trivia.cs:18:1:18:19 | #line ... | trivia.cs:21:1:21:13 | #line default | +| trivia.cs:18:1:18:22 | #line ... | trivia.cs:21:1:21:13 | #line default | | trivia.cs:21:1:21:13 | #line default | trivia.cs:25:1:25:38 | #line hidden | -| trivia.cs:25:1:25:38 | #line hidden | trivia.cs:27:1:27:9 | #line ... | +| trivia.cs:25:1:25:38 | #line hidden | trivia.cs:27:1:27:7 | #line ... | last -| trivia.cs:27:1:27:9 | #line ... | +| trivia.cs:27:1:27:7 | #line ... | +mapped +| trivia.cs:19:9:19:11 | trivia.cs:19:9:19:11 | comments1.cs:1:9:1:11 | comments1.cs:1:9:1:11 | +| trivia.cs:19:9:19:14 | trivia.cs:19:9:19:14 | comments1.cs:1:9:1:14 | comments1.cs:1:9:1:14 | +| trivia.cs:19:13:19:13 | trivia.cs:19:13:19:13 | comments1.cs:1:13:1:13 | comments1.cs:1:13:1:13 | +| trivia.cs:20:9:20:11 | trivia.cs:20:9:20:11 | comments1.cs:2:9:2:11 | comments1.cs:2:9:2:11 | +| trivia.cs:20:9:20:14 | trivia.cs:20:9:20:14 | comments1.cs:2:9:2:14 | comments1.cs:2:9:2:14 | +| trivia.cs:20:13:20:13 | trivia.cs:20:13:20:13 | comments1.cs:2:13:2:13 | comments1.cs:2:13:2:13 | +| trivia.cs:21:1:21:13 | trivia.cs:21:1:21:13 | comments1.cs:3:1:3:13 | comments1.cs:3:1:3:13 | diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.ql b/csharp/ql/test/library-tests/comments/LineDirectives.ql index 4fa2adedb9d..5b009f0b4b8 100644 --- a/csharp/ql/test/library-tests/comments/LineDirectives.ql +++ b/csharp/ql/test/library-tests/comments/LineDirectives.ql @@ -4,11 +4,16 @@ query predicate default(DefaultLineDirective line) { any() } query predicate hidden(HiddenLineDirective line) { any() } -query predicate lines(NumericLineDirective line, int l, string file) { - line.getLine() = l and - if line.hasFileName() then line.getFileName() = file else file = "no file" +query predicate lines_file(NumericLineDirective line, int l, File file) { + line.getLine() = l and line.getReferencedFile() = file +} + +query predicate lines_no_file(NumericLineDirective line, int l) { + line.getLine() = l and not exists(line.getReferencedFile()) } query predicate succ(LineDirective d, LineDirective succ) { d.getSuccLineDirective() = succ } query predicate last(LineDirective d) { not d.hasSuccLineDirective() } + +query predicate mapped(SourceLocation l1, Location l2) { l1.getMappedLocation() = l2 } diff --git a/csharp/ql/test/library-tests/comments/PragmaChecksums.expected b/csharp/ql/test/library-tests/comments/PragmaChecksums.expected index 185e834cbdf..d3700c13aa0 100644 --- a/csharp/ql/test/library-tests/comments/PragmaChecksums.expected +++ b/csharp/ql/test/library-tests/comments/PragmaChecksums.expected @@ -1 +1 @@ -| trivia.cs:13:1:13:98 | #pragma checksum ... | "file.cs" | "{406EA660-64CF-4C82-B6F0-42D48172A799}" | "ab007f1d23d9" | +| trivia.cs:13:1:13:103 | #pragma checksum ... | comments1.cs:0:0:0:0 | comments1.cs | "{406EA660-64CF-4C82-B6F0-42D48172A799}" | "ab007f1d23d9" | diff --git a/csharp/ql/test/library-tests/comments/PragmaChecksums.ql b/csharp/ql/test/library-tests/comments/PragmaChecksums.ql index 7d3f10ab3b5..8de177f5215 100644 --- a/csharp/ql/test/library-tests/comments/PragmaChecksums.ql +++ b/csharp/ql/test/library-tests/comments/PragmaChecksums.ql @@ -1,4 +1,4 @@ import csharp from PragmaChecksumDirective p -select p, p.getFileName(), p.getGuid(), p.getBytes() +select p, p.getReferencedFile(), p.getGuid(), p.getBytes() diff --git a/csharp/ql/test/library-tests/comments/PrintAst.expected b/csharp/ql/test/library-tests/comments/PrintAst.expected index 96f0f088501..eeb7993eaef 100644 --- a/csharp/ql/test/library-tests/comments/PrintAst.expected +++ b/csharp/ql/test/library-tests/comments/PrintAst.expected @@ -132,11 +132,15 @@ trivia.cs: # 16| 5: [Method] M1 # 16| -1: [TypeMention] Void # 17| 4: [BlockStmt] {...} -# 19| 0: [LocalVariableDeclStmt] ... ...; -# 19| 0: [LocalVariableDeclExpr] Int32 i +comments1.cs: +# 1| 0: [LocalVariableDeclStmt] ... ...; +# 1| 0: [LocalVariableDeclExpr] Int32 i +trivia.cs: # 19| 0: [TypeMention] int -# 20| 1: [LocalVariableDeclStmt] ... ...; -# 20| 0: [LocalVariableDeclExpr] Int32 j +comments1.cs: +# 2| 1: [LocalVariableDeclStmt] ... ...; +# 2| 0: [LocalVariableDeclExpr] Int32 j +trivia.cs: # 20| 0: [TypeMention] int # 22| 2: [LocalVariableDeclStmt] ... ...; # 22| 0: [LocalVariableDeclExpr] Char c diff --git a/csharp/ql/test/library-tests/comments/trivia.cs b/csharp/ql/test/library-tests/comments/trivia.cs index 61cfe454409..be670eac1c4 100644 --- a/csharp/ql/test/library-tests/comments/trivia.cs +++ b/csharp/ql/test/library-tests/comments/trivia.cs @@ -10,12 +10,12 @@ using System.Collections; using System.Collections.Generic; #pragma warning disable 414, CS3021 -#pragma checksum "file.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "ab007f1d23d9" // New checksum +#pragma checksum "comments1.cs" "{406EA660-64CF-4C82-B6F0-42D48172A799}" "ab007f1d23d9" // New checksum class Tr1 { static void M1() { -#line 200 "Special" +#line 1 "comments1.cs" int i; int j; #line default @@ -24,7 +24,7 @@ class Tr1 float f; #line hidden // numbering not affected string s; -#line 300 +#line 5 double d; } } From 899e52a68ac82df1c6a97a9998f452139ad9006b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 28 Jan 2021 15:51:48 +0100 Subject: [PATCH 133/429] Adjust getMappedLocation to not include line directives --- csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll | 8 ++------ csharp/ql/src/semmle/code/csharp/Location.qll | 5 ++++- .../test/library-tests/comments/LineDirectives.expected | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll index 5d140b17968..c7c7bfe00e8 100644 --- a/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll +++ b/csharp/ql/src/semmle/code/csharp/ExprOrStmtParent.qll @@ -58,13 +58,9 @@ private module Cached { cached Location bestLocation(Element e) { result = e.getALocation().(SourceLocation) and - ( - not exists(e.getALocation().(SourceLocation).getMappedLocation()) or - e instanceof LineDirective - ) + not exists(e.getALocation().(SourceLocation).getMappedLocation()) or - result = e.getALocation().(SourceLocation).getMappedLocation() and - not e instanceof LineDirective + result = e.getALocation().(SourceLocation).getMappedLocation() or hasNoSourceLocation(e) and result = min(Location l | l = e.getALocation() | l order by l.getFile().toString()) diff --git a/csharp/ql/src/semmle/code/csharp/Location.qll b/csharp/ql/src/semmle/code/csharp/Location.qll index 5d35933f246..97f9302c474 100644 --- a/csharp/ql/src/semmle/code/csharp/Location.qll +++ b/csharp/ql/src/semmle/code/csharp/Location.qll @@ -63,7 +63,10 @@ class EmptyLocation extends Location { */ class SourceLocation extends Location, @location_default { /** Gets the location that takes into account `#line` directives, if any. */ - Location getMappedLocation() { locations_mapped(this, result) } + Location getMappedLocation() { + locations_mapped(this, result) and + not exists(LineDirective l | l.getALocation() = this) + } override File getFile() { locations_default(this, result, _, _, _, _) } diff --git a/csharp/ql/test/library-tests/comments/LineDirectives.expected b/csharp/ql/test/library-tests/comments/LineDirectives.expected index 58b54de85e6..13c3658fe82 100644 --- a/csharp/ql/test/library-tests/comments/LineDirectives.expected +++ b/csharp/ql/test/library-tests/comments/LineDirectives.expected @@ -19,4 +19,3 @@ mapped | trivia.cs:20:9:20:11 | trivia.cs:20:9:20:11 | comments1.cs:2:9:2:11 | comments1.cs:2:9:2:11 | | trivia.cs:20:9:20:14 | trivia.cs:20:9:20:14 | comments1.cs:2:9:2:14 | comments1.cs:2:9:2:14 | | trivia.cs:20:13:20:13 | trivia.cs:20:13:20:13 | comments1.cs:2:13:2:13 | comments1.cs:2:13:2:13 | -| trivia.cs:21:1:21:13 | trivia.cs:21:1:21:13 | comments1.cs:3:1:3:13 | comments1.cs:3:1:3:13 | From fd09883bfeed4e69ad891f0e4d175d8274885d4f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 1 Feb 2021 09:33:52 +0100 Subject: [PATCH 134/429] Add change notes for preprocessor directives --- csharp/change-notes/2021-02-01-Preprocessor-directives.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 csharp/change-notes/2021-02-01-Preprocessor-directives.md diff --git a/csharp/change-notes/2021-02-01-Preprocessor-directives.md b/csharp/change-notes/2021-02-01-Preprocessor-directives.md new file mode 100644 index 00000000000..d81979c36cd --- /dev/null +++ b/csharp/change-notes/2021-02-01-Preprocessor-directives.md @@ -0,0 +1,8 @@ +lgtm,codescanning +* The `PreprocessorDirective` class and its base classes have been added to support +preprocessor directives, such as `#if`, `#define`, `#undef`, `#line`, `#region`, +`#warning`, `#error`, `#pragma warning`, `#pragma checksum` and `#nullable`. Furthermore, +`#line` directives are now taken into account when querying the location of any +code construct. Files referenced in preprocessor directives are also included in the +extraction sources. This change is expected to lead to better error reporting locations +in generated code, such as generated code from `.cshtml` files in ASP.NET Core. From dbe656fe6a2da2b1dbd79d6d2f1499c668fbf5cb Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 1 Feb 2021 09:48:18 +0100 Subject: [PATCH 135/429] Add DB upgrade folder for preprocessor directives --- .../old.dbscheme | 1959 ++++++++++++++++ .../semmlecode.csharp.dbscheme | 2070 +++++++++++++++++ .../upgrade.properties | 5 + 3 files changed, 4034 insertions(+) create mode 100644 csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/old.dbscheme create mode 100644 csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/semmlecode.csharp.dbscheme create mode 100644 csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/upgrade.properties diff --git a/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/old.dbscheme b/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/old.dbscheme new file mode 100644 index 00000000000..efcd69e086a --- /dev/null +++ b/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/old.dbscheme @@ -0,0 +1,1959 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_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 + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file 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 +); + +diagnostics( + unique int id: @diagnostic, + 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 +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string 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`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +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); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +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); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/semmlecode.csharp.dbscheme b/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..68db341c2ed --- /dev/null +++ b/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/semmlecode.csharp.dbscheme @@ -0,0 +1,2070 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_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 + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file 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 +); + +diagnostics( + unique int id: @diagnostic, + 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 +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string 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`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +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); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +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); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref +) + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/upgrade.properties b/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/upgrade.properties new file mode 100644 index 00000000000..14ab5d3a87c --- /dev/null +++ b/csharp/upgrades/efcd69e086a26dd33395f2ddb3113b2849399040/upgrade.properties @@ -0,0 +1,5 @@ +description: Add '@preprocessor_directive' to store preprocessor directives. Add +'locations_mapped' relation to store location that take into account '#line' +directives. Finally, the '@define_symbol_expr' expression was added to represent +symbols inside conditions of '#if' and '#elif' directives. +compatibility: backwards From d3244fe298b3886e3e508ec4b61de633e6f11748 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 1 Feb 2021 13:24:41 +0100 Subject: [PATCH 136/429] Add new .stats file --- .../ql/src/semmlecode.csharp.dbscheme.stats | 18048 +++++++++------- 1 file changed, 10097 insertions(+), 7951 deletions(-) diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index 5cddf1536bb..c294897e009 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -1,7 +1,7 @@ @compilation -1095 +564 @diagnostic @@ -9,7 +9,7 @@ @extractor_message -7611 +750 @externalDefect @@ -21,11 +21,11 @@ @externalDataElement -29 +15 @duplication -22736 +11701 @similarity @@ -33,139 +33,195 @@ @location_default -14071994 +11326677 @assembly -4198 +2160 @file -42467 +24351 @folder -16940 +9177 @namespace -21942 +11293 @namespace_declaration -19760 +8355 @using_namespace_directive -144253 +66100 @using_static_directive -390 +199 + + +@directive_if +2550 + + +@directive_elif +7 + + +@directive_else +1140 + + +@directive_endif +2550 + + +@directive_region +565 + + +@directive_endregion +565 + + +@directive_line +128896 + + +@directive_nullable +83477 + + +@directive_warning +1 + + +@directive_error +1 + + +@directive_undefine +1 + + +@directive_define +5 + + +@pragma_checksum +2494 + + +@pragma_warning +14725 @bool_type -4 +2 @char_type -4 +2 @decimal_type -4 +2 @sbyte_type -4 +2 @short_type -4 +2 @int_type -4 +2 @long_type -4 +2 @byte_type -4 +2 @ushort_type -4 +2 @uint_type -4 +2 @ulong_type -4 +2 @float_type -4 +2 @double_type -4 +2 @enum_type -11952 +6141 @struct_type -49665 +24822 @class_type -305101 +154426 @interface_type -178114 +88664 @delegate_type -107568 +52237 @null_type -4 +2 @type_parameter -202599 +102321 @pointer_type -219 +112 @nullable_type -979 +550 @array_type -9122 +4384 @void_type -4 +2 @int_ptr_type -4 +2 @tuple_type -1782 +857 @uint_ptr_type @@ -173,7 +229,7 @@ @dynamic_type -4 +2 @arglist_type @@ -185,495 +241,495 @@ @function_pointer_type -11 +9 @typeref -234794 +120781 @attribute -745432 +368399 @type_mention -1248753 +622003 @oblivious -1315 +664 @not_annotated -618 +300 @annotated -113 +75 @type_parameter_constraints -591856 +273733 @modifier -82 +42 @property -423531 +212542 @indexer -17042 +7590 @getter -440340 +220012 @setter -127528 +64470 @event -15230 +7838 @add_event_accessor -15230 +7838 @remove_event_accessor -15230 +7838 @operator -12410 +6201 @method -1116872 +549172 @constructor -277641 +138720 @destructor -443 +225 @local_function -1801 +488 @addressable_field -370470 +188270 @constant -185215 +95194 @addressable_local_variable -162452 +72587 @local_constant -799 +373 @local_variable_ref -265 +67 @parameter -2417684 +1189134 @block_stmt -307634 +159797 @expr_stmt -367212 +178398 @return_stmt -94725 +40051 @using_block_stmt -1145 +517 @var_decl_stmt -147598 +67553 @if_stmt -118155 +50740 @switch_stmt -3077 +1447 @while_stmt -4464 +1984 @do_stmt -985 +386 @for_stmt -6820 +3124 @foreach_stmt -5352 +1910 @break_stmt -11046 +5413 @continue_stmt -2226 +1168 @goto_stmt -2744 +1045 @goto_case_stmt -330 +154 @goto_default_stmt -145 +61 @throw_stmt -75420 +50988 @yield_stmt -680 +194 @try_stmt -4310 +2011 @checked_stmt -254 +146 @unchecked_stmt -104 +36 @lock_stmt -1529 +496 @const_decl_stmt -799 +373 @empty_stmt -352 +115 @unsafe_stmt -183 +53 @fixed_stmt -1152 +496 @label_stmt -1021 +423 @catch -3432 +1719 @case_stmt -22805 +10966 @local_function_stmt -1792 +488 @using_decl_stmt -551 +189 @bool_literal_expr -69557 +40242 @int_literal_expr -753725 +408062 @long_literal_expr -333 +153 @double_literal_expr -868 +337 @string_literal_expr -411647 +207177 @null_literal_expr -108228 +64946 @local_variable_access_expr -522589 +233847 @parameter_access_expr -355035 +146824 @field_access_expr -459632 +226547 @property_access_expr -359107 +168128 @type_access_expr -346630 +170095 @typeof_expr -30028 +23893 @method_invocation_expr -547069 +259436 @cast_expr -265245 +107752 @object_creation_expr -62749 +28063 @array_creation_expr -180004 +90105 @array_init_expr -179553 +89964 @local_var_decl_expr -163320 +72969 @char_literal_expr -16245 +8057 @decimal_literal_expr -93 +49 @uint_literal_expr -2416 +811 @ulong_literal_expr -391 +189 @float_literal_expr -456 +123 @this_access_expr -591822 +293267 @base_access_expr -2851 +1617 @method_access_expr -9222 +3188 @event_access_expr -435 +162 @indexer_access_expr -30758 +14740 @array_access_expr -19431 +10091 @delegate_invocation_expr -2009 +783 @operator_invocation_expr -29946 +12666 @explicit_delegate_creation_expr -682 +482 @implicit_delegate_creation_expr -5109 +2546 @default_expr -6168 +3354 @plus_expr -46 +12 @minus_expr -7096 +2658 @bit_not_expr -740 +264 @log_not_expr -26384 +12491 @post_incr_expr -12359 +5382 @post_decr_expr -1703 +698 @pre_incr_expr -1266 +671 @pre_decr_expr -407 +125 @mul_expr -4645 +1387 @div_expr -1798 +612 @rem_expr -707 +276 @add_expr -27859 +12723 @sub_expr -12621 +4948 @lshift_expr -4137 +914 @rshift_expr -1769 +707 @lt_expr -15983 +6804 @gt_expr -9416 +3980 @le_expr -3844 +1422 @ge_expr -6037 +2380 @eq_expr -53720 +23261 @ne_expr -37361 +16042 @bit_and_expr -6322 +2303 @bit_xor_expr -530 +217 @bit_or_expr -15286 +6954 @log_and_expr -20460 +9148 @log_or_expr -14050 +6420 @is_expr -6511 +3108 @as_expr -2739 +1363 @null_coalescing_expr -3629 +1422 @conditional_expr -9007 +3413 @simple_assign_expr -167204 +79093 @assign_add_expr @@ -681,67 +737,67 @@ @assign_sub_expr -1025 +434 @assign_mul_expr -183 +81 @assign_div_expr -99 +44 @assign_rem_expr -14 +3 @assign_and_expr -341 +103 @assign_xor_expr -114 +49 @assign_or_expr -1418 +562 @assign_lshift_expr -118 +31 @assign_rshift_expr -217 +64 @object_init_expr -7685 +3456 @collection_init_expr -594 +265 @checked_expr -328 +140 @unchecked_expr -1426 +609 @constructor_init_expr -5818 +3163 @add_event_expr -173 +63 @remove_event_expr -122 +53 @par_expr @@ -749,11 +805,11 @@ @lambda_expr -48769 +23125 @anonymous_method_expr -86 +41 @namespace_expr @@ -761,35 +817,35 @@ @dynamic_element_access_expr -331 +117 @dynamic_member_access_expr -6843 +2975 @pointer_indirection_expr -4157 +1878 @address_of_expr -1294 +475 @sizeof_expr -1065 +255 @await_expr -54750 +25782 @nameof_expr -15644 +5774 @interpolated_string_expr -3042 +894 @unknown_expr @@ -797,71 +853,71 @@ @throw_expr -1532 +643 @tuple_expr -1450 +440 @local_function_invocation_expr -7490 +1187 @ref_expr -461 +124 @discard_expr -903 +317 @range_expr -33 +15 @index_expr -47 +21 @switch_expr -510 +199 @recursive_pattern_expr -1011 +199 @property_pattern_expr -836 +154 @positional_pattern_expr -172 +45 @switch_case_expr -4350 +2068 @assign_coalesce_expr -546 +183 @suppress_nullable_warning_expr -13902 +5940 @namespace_access_expr -20 +11 @lt_pattern_expr -2 +1 @gt_pattern_expr -5 +2 @le_pattern_expr @@ -873,23 +929,27 @@ @not_pattern_expr -71 +19 @and_pattern_expr -3 +2 @or_pattern_expr -34 +21 @function_pointer_invocation_expr 4 +@define_symbol_expr +3314 + + @xmldtd -6 +5 @xmlelement @@ -913,19 +973,19 @@ @singlelinecomment -189286 +86064 @multilinecomment -22654 +7533 @xmldoccomment -208748 +638 @commentblock -147866 +42325 @asp_close_tag @@ -965,7 +1025,7 @@ @cil_nop -840543 +712327 @cil_break @@ -973,147 +1033,147 @@ @cil_ldarg_0 -3969685 +2043128 @cil_ldarg_1 -1214962 +625320 @cil_ldarg_2 -443257 +228137 @cil_ldarg_3 -208872 +107503 @cil_ldloc_0 -927959 +477604 @cil_ldloc_1 -493235 +253859 @cil_ldloc_2 -288317 +148392 @cil_ldloc_3 -191791 +98711 @cil_stloc_0 -524232 +269813 @cil_stloc_1 -260145 +133892 @cil_stloc_2 -198035 +101925 @cil_stloc_3 -138107 +71081 @cil_ldarg_s -264149 +135953 @cil_ldarga_s -74666 +38429 @cil_starg_s -37124 +19107 @cil_ldloc_s -685421 +352774 @cil_ldloca_s -628376 +323414 @cil_stloc_s -480182 +247141 @cil_ldnull -602888 +310296 @cil_ldc_i4_m1 -126027 +64864 @cil_ldc_i4_0 -624723 +321534 @cil_ldc_i4_1 -493975 +254240 @cil_ldc_i4_2 -120865 +62207 @cil_ldc_i4_3 -64063 +32972 @cil_ldc_i4_4 -58798 +30262 @cil_ldc_i4_5 -38629 +19881 @cil_ldc_i4_6 -23232 +11957 @cil_ldc_i4_7 -20724 +10666 @cil_ldc_i4_8 -33436 +17209 @cil_ldc_i4_s -422752 +217583 @cil_ldc_i4 -510151 +262565 @cil_ldc_i8 -4880 +2511 @cil_ldc_r4 -10247 +5274 @cil_ldc_r8 -10316 +5309 @cil_dup -841033 +432865 @cil_pop -256113 +131816 @cil_jmp @@ -1121,7 +1181,7 @@ @cil_call -2738046 +1409225 @cil_calli @@ -1129,283 +1189,283 @@ @cil_ret -1784218 +918306 @cil_br_s -345387 +191079 @cil_brfalse_s -465385 +239525 @cil_brtrue_s -430170 +221401 @cil_beq_s -82158 +42285 @cil_bge_s -34883 +17953 @cil_bgt_s -16477 +8480 @cil_ble_s -29165 +15010 @cil_blt_s -60858 +31322 @cil_bne_un_s -102531 +52771 @cil_bge_un_s -2182 +1123 @cil_bgt_un_s -8723 +4489 @cil_ble_un_s -6112 +3146 @cil_blt_un_s -1466 +754 @cil_br -96039 +49429 @cil_brfalse -32355 +16652 @cil_brtrue -27299 +14050 @cil_beq -21484 +11057 @cil_bge -1388 +714 @cil_bgt -1461 +752 @cil_ble -4636 +2386 @cil_blt -7924 +4078 @cil_bne_un -7228 +3720 @cil_bge_un -143 +140 @cil_bgt_un -691 +355 @cil_ble_un -1100 +566 @cil_blt_un -180 +92 @cil_switch -23851 +12275 @cil_ldind_i1 -88 +75 @cil_ldind_u1 -5503 +3165 @cil_ldind_i2 -511 - - -@cil_ldind_u2 -2505 - - -@cil_ldind_i4 -9765 - - -@cil_ldind_u4 -1480 - - -@cil_ldind_i8 -1967 - - -@cil_ldind_i -250 - - -@cil_ldind_r4 -701 - - -@cil_ldind_r8 263 +@cil_ldind_u2 +2123 + + +@cil_ldind_i4 +5026 + + +@cil_ldind_u4 +762 + + +@cil_ldind_i8 +1012 + + +@cil_ldind_i +212 + + +@cil_ldind_r4 +360 + + +@cil_ldind_r8 +135 + + @cil_ldind_ref -6648 +3421 @cil_stind_ref -16915 +8706 @cil_stind_i1 -8513 +4381 @cil_stind_i2 -1410 +1195 @cil_stind_i4 -10350 +5705 @cil_stind_i8 -2342 +1205 @cil_stind_r4 -185 +105 @cil_stind_r8 -224 +115 @cil_add -223713 +115141 @cil_sub -85182 +43842 @cil_mul -29915 +15396 @cil_div -9112 +4690 @cil_div_un -253 +194 @cil_rem -3404 +1752 @cil_rem_un -228 +117 @cil_and -59265 +30503 @cil_or -22122 +11386 @cil_xor -22687 +11676 @cil_shl -18946 +9751 @cil_shr -9166 +4717 @cil_shr_un -26077 +13421 @cil_neg -2333 +1200 @cil_not -1456 +749 @cil_conv_i1 -1383 +711 @cil_conv_i2 -1446 +744 @cil_conv_i4 -59709 +30731 @cil_conv_i8 -50230 +25852 @cil_conv_r4 -2464 +1268 @cil_conv_r8 -5274 +2714 @cil_conv_u4 -7822 +4025 @cil_conv_u8 -19521 +10047 @cil_callvirt -2048017 +1054079 @cil_cpobj @@ -1413,27 +1473,27 @@ @cil_ldobj -12639 +6505 @cil_ldstr -925665 +476424 @cil_newobj -656304 +337788 @cil_castclass -96955 +49901 @cil_isinst -56382 +29019 @cil_conv_r_un -263 +135 @cil_unbox @@ -1441,59 +1501,59 @@ @cil_throw -380781 +271796 @cil_ldfld -1674741 +861960 @cil_ldflda -300353 +154586 @cil_stfld -1071843 +551659 @cil_ldsfld -406864 +209405 @cil_ldsflda -2527 +1301 @cil_stsfld -130767 +67303 @cil_stobj -7013 +3609 @cil_conv_ovf_i1_un -19 +10 @cil_conv_ovf_i2_un -14 +7 @cil_conv_ovf_i4_un -170 +87 @cil_conv_ovf_i8_un -29 +15 @cil_conv_ovf_u1_un -19 +10 @cil_conv_ovf_u2_un -9 +5 @cil_conv_ovf_u4_un @@ -1505,7 +1565,7 @@ @cil_conv_ovf_i_un -131 +67 @cil_conv_ovf_u_un @@ -1513,139 +1573,139 @@ @cil_box -79747 +41044 @cil_newarr -111980 +57634 @cil_ldlen -55267 +28445 @cil_ldelema -9858 +5073 @cil_ldelem_i1 -175 +90 @cil_ldelem_u1 -15556 +8006 @cil_ldelem_i2 -428 +220 @cil_ldelem_u2 -6083 +3131 @cil_ldelem_i4 -17563 +9039 @cil_ldelem_u4 -19092 +9826 @cil_ldelem_i8 -11908 +6129 @cil_ldelem_i -14 +7 @cil_ldelem_r4 -282 +145 @cil_ldelem_r8 -457 +235 @cil_ldelem_ref -30665 +15783 @cil_stelem_i -14 +11 @cil_stelem_i1 -8781 +4519 @cil_stelem_i2 -8976 +4620 @cil_stelem_i4 -22799 +11734 @cil_stelem_i8 -9414 +4845 @cil_stelem_r4 -199 +102 @cil_stelem_r8 -477 +245 @cil_stelem_ref -362526 +186586 @cil_ldelem -2274 +1170 @cil_stelem -53557 +27565 @cil_unbox_any -14373 +7397 @cil_conv_ovf_i1 -24 +12 @cil_conv_ovf_u1 -112 +57 @cil_conv_ovf_i2 -77 +40 @cil_conv_ovf_u2 -53 +27 @cil_conv_ovf_i4 -287 +147 @cil_conv_ovf_u4 -77 +40 @cil_conv_ovf_i8 -14 +7 @cil_conv_ovf_u8 -29 +23 @cil_refanyval @@ -1661,23 +1721,23 @@ @cil_ldtoken -71233 +36662 @cil_conv_u2 -4334 +2231 @cil_conv_u1 -11246 +5788 @cil_conv_i -3754 +3181 @cil_conv_ovf_i -267 +137 @cil_conv_ovf_u @@ -1685,47 +1745,47 @@ @cil_add_ovf -1729 +889 @cil_add_ovf_un -150 +77 @cil_mul_ovf -443 +228 @cil_mul_ovf_un -253 +195 @cil_sub_ovf -1110 +571 @cil_sub_ovf_un -29 +15 @cil_endfinally -56835 +29252 @cil_leave -66786 +34373 @cil_leave_s -149173 +76776 @cil_stind_i -128 +108 @cil_conv_u -5954 +5046 @cil_arglist @@ -1733,31 +1793,31 @@ @cil_ceq -99414 +84249 @cil_cgt -11858 +10049 @cil_cgt_un -37633 +31892 @cil_clt -20013 +16960 @cil_clt_un -1347 +1141 @cil_ldftn -79839 +41092 @cil_ldvirtftn -1110 +571 @cil_ldarg @@ -1785,11 +1845,11 @@ @cil_localloc -1002 +849 @cil_endfilter -808 +416 @cil_unaligned @@ -1797,7 +1857,7 @@ @cil_volatile -8528 +4389 @cil_tail @@ -1805,27 +1865,27 @@ @cil_initobj -101660 +52322 @cil_constrained -25283 +13012 @cil_cpblk -19 +10 @cil_initblk -4 +2 @cil_rethrow -3765 +1937 @cil_sizeof -1729 +889 @cil_refanytype @@ -1833,23 +1893,23 @@ @cil_readonly -34 +17 @cil_valueorreftype -595251 +306365 @cil_typeparameter -184753 +95089 @cil_array_type -14168 +7292 @cil_pointer_type -599 +308 @cil_function_pointer_type @@ -1857,64 +1917,64 @@ @cil_method -2311748 +1189816 @cil_method_implementation -1725702 +888189 @cil_field -1008310 +518960 @cil_parameter -4546452 +2339980 @cil_property -379895 +195525 @cil_event -20841 +10726 @cil_local_variable -1150606 +592197 @cil_catch_handler -43806 +22546 @cil_filter_handler -808 +416 @cil_finally_handler -55364 +28495 @cil_fault_handler -1470 +757 @cil_attribute -328261 +168950 compilations -1095 +564 id -1095 +564 cwd -784 +403 @@ -1928,7 +1988,7 @@ 1 2 -1095 +564 @@ -1944,12 +2004,12 @@ 1 2 -472 +243 2 3 -311 +160 @@ -1959,19 +2019,19 @@ compilation_args -4904 +2524 id -1095 +564 num -24 +12 arg -1120 +576 @@ -1985,12 +2045,12 @@ 4 5 -574 +295 5 6 -521 +268 @@ -2006,12 +2066,12 @@ 4 5 -574 +295 5 6 -521 +268 @@ -2027,12 +2087,12 @@ 107 108 -4 +2 225 226 -19 +10 @@ -2048,17 +2108,17 @@ 2 3 -14 +7 107 108 -4 +2 119 120 -4 +2 @@ -2074,850 +2134,720 @@ 1 2 -1095 - - -107 -226 -24 - - - - - - -arg -num - - -12 - - -1 -2 -1110 - - -2 -3 -9 - - - - - - - - -compilation_compiling_files -22585 - - -id -1095 - - -num -711 - - -file -22580 - - - - -id -num - - -12 - - -1 -3 -48 - - -3 -4 -58 - - -4 -5 -82 - - -5 -6 -87 - - -6 -7 -68 - - -7 -9 -97 - - -9 -12 -87 - - -12 -15 -82 - - -15 -17 -82 - - -17 -21 -82 - - -21 -27 -87 - - -28 -37 -82 - - -37 -65 -82 - - -67 -147 -63 - - - - - - -id -file - - -12 - - -1 -3 -48 - - -3 -4 -58 - - -4 -5 -82 - - -5 -6 -87 - - -6 -7 -68 - - -7 -9 -97 - - -9 -12 -87 - - -12 -15 -82 - - -15 -17 -82 - - -17 -21 -82 - - -21 -27 -87 - - -28 -37 -82 - - -37 -65 -82 - - -67 -147 -63 - - - - - - -num -id - - -12 - - -1 -3 -43 - - -3 -4 -29 - - -4 -5 -58 - - -5 -6 -9 - - -6 -7 -97 - - -7 -11 -53 - - -11 -12 -77 - - -12 -18 -63 - - -18 -24 -53 - - -25 -33 -53 - - -38 -52 -53 - - -56 -103 -53 - - -108 -216 -53 - - -217 -226 -9 - - - - - - -num -file - - -12 - - -1 -3 -43 - - -3 -4 -29 - - -4 -5 -58 - - -5 -6 -9 - - -6 -7 -97 - - -7 -11 -53 - - -11 -12 -77 - - -12 -18 -63 - - -18 -24 -53 - - -25 -33 -53 - - -38 -52 -53 - - -56 -103 -53 - - -108 -216 -53 - - -217 -226 -9 - - - - - - -file -id - - -12 - - -1 -2 -22575 - - -2 -3 -4 - - - - - - -file -num - - -12 - - -1 -2 -22575 - - -2 -3 -4 - - - - - - - - -compilation_referencing_files -359263 - - -id -1095 - - -num -2742 - - -file -3414 - - - - -id -num - - -12 - - -5 -284 -92 - - -284 -288 -87 - - -288 -292 -92 - - -293 -309 -87 - - -309 -311 -92 - - -311 -328 -82 - - -328 -344 -73 - - -344 -346 -97 - - -346 -349 -87 - - -349 -353 -87 - - -353 -359 -92 - - -359 -369 -82 - - -369 -564 -38 - - - - - - -id -file - - -12 - - -5 -284 -92 - - -284 -288 -87 - - -288 -292 -92 - - -293 -309 -87 - - -309 -311 -92 - - -311 -328 -82 - - -328 -344 -73 - - -344 -346 -97 - - -346 -349 -87 - - -349 -353 -87 - - -353 -359 -92 - - -359 -369 -82 - - -369 -564 -38 - - - - - - -num -id - - -12 - - -1 -4 -219 - - -4 -7 -29 - - -7 -8 -696 - - -8 -118 -219 - - -118 -214 -204 - - -222 -223 -638 - - -224 -225 -711 - - -225 -226 -24 - - - - - - -num -file - - -12 - - -1 -4 -219 - - -4 -5 -9 - - -5 -6 -579 - - -6 -16 -214 - - -16 -23 -224 - - -23 -29 -214 - - -29 -34 -209 - - -34 -43 -243 - - -43 -55 -209 - - -55 -61 -209 - - -61 -64 -219 - - -64 -72 -189 - - - - - - -file -id - - -12 - - -1 -2 -526 - - -2 -5 -258 - - -6 -7 -4 - - -7 -8 -316 - - -8 -10 -277 - - -10 -23 -258 - - -23 -122 -258 - - -124 -214 -243 - - -220 -221 -73 - - -222 -223 -482 - - -224 -225 -715 - - - - - - -file -num - - -12 - - -1 -2 564 +107 +226 +12 + + + + + + +arg +num + + +12 + + +1 +2 +571 + + 2 +3 +5 + + + + + + + + +compilation_compiling_files +12395 + + +id +548 + + +num +1435 + + +file +10384 + + + + +id +num + + +12 + + +3 +4 +1 + + +4 5 -253 +155 5 6 -165 +151 6 7 -311 +36 7 10 -272 +43 10 +17 +41 + + +17 +31 +41 + + +31 +59 +41 + + +59 +1359 +36 + + + + + + +id +file + + +12 + + +3 +4 +1 + + +4 +5 +155 + + +5 +6 +151 + + +6 +7 +36 + + +7 +10 +43 + + +10 +17 +41 + + +17 +31 +41 + + +31 +59 +41 + + +59 +1359 +36 + + + + + + +num +id + + +12 + + +1 +2 +739 + + +2 +3 +411 + + +3 +17 +118 + + +17 +38 +108 + + +38 +520 +57 + + + + + + +num +file + + +12 + + +1 +2 +739 + + +2 +3 +411 + + +3 +16 +116 + + +16 +36 +109 + + +36 +476 +58 + + + + + + +file +id + + +12 + + +1 +2 +9343 + + +2 +3 +822 + + +3 +187 +218 + + + + + + +file +num + + +12 + + +1 +2 +9831 + + +2 +78 +552 + + + + + + + + +compilation_referencing_files +184906 + + +id +564 + + +num +1411 + + +file +1757 + + + + +id +num + + +12 + + +5 +284 +47 + + +284 +288 +45 + + +288 +292 +47 + + +293 +309 +45 + + +309 +311 +47 + + +311 +328 +42 + + +328 +344 +37 + + +344 +346 +50 + + +346 +349 +45 + + +349 +353 +45 + + +353 +359 +47 + + +359 +369 +42 + + +369 +564 +20 + + + + + + +id +file + + +12 + + +5 +284 +47 + + +284 +288 +45 + + +288 +292 +47 + + +293 +309 +45 + + +309 +311 +47 + + +311 +328 +42 + + +328 +344 +37 + + +344 +346 +50 + + +346 +349 +45 + + +349 +353 +45 + + +353 +359 +47 + + +359 +369 +42 + + +369 +564 +20 + + + + + + +num +id + + +12 + + +1 +4 +112 + + +4 +7 +15 + + +7 +8 +358 + + +8 +118 +112 + + +118 +214 +105 + + +222 +223 +328 + + +224 +225 +365 + + +225 +226 +12 + + + + + + +num +file + + +12 + + +1 +4 +112 + + +4 +5 +5 + + +5 +6 +338 + + +6 20 -287 +125 + + +20 +27 +115 + + +27 +32 +122 + + +32 +38 +112 + + +38 +50 +107 + + +50 +60 +112 + + +60 +62 +100 + + +62 +65 +110 + + +65 +71 +47 + + + + + + +file +id + + +12 + + +1 +2 +270 + + +2 +5 +132 + + +6 +7 +2 + + +7 +8 +162 + + +8 +10 +142 + + +10 +23 +132 + + +23 +122 +132 + + +124 +214 +125 + + +220 +221 +37 + + +222 +223 +248 + + +224 +225 +368 + + + + + + +file +num + + +12 + + +1 +2 +290 + + +2 +5 +155 + + +5 +6 +95 + + +6 +7 +155 + + +7 +11 +135 + + +11 +20 +137 20 25 -311 +132 25 -30 -287 +29 +135 -30 -59 -258 +29 +48 +132 -59 -63 -272 +49 +62 +120 -63 -65 -185 +62 +64 +105 -65 -78 -243 +64 +68 +150 + + +68 +72 +10 @@ -2927,23 +2857,23 @@ compilation_time -7671 +3948 id -1095 +564 num -4 +2 kind -34 +17 seconds -5523 +2862 @@ -2957,7 +2887,7 @@ 1 2 -1095 +564 @@ -2973,7 +2903,7 @@ 7 8 -1095 +564 @@ -2987,9 +2917,14 @@ 12 +6 +7 +2 + + 7 8 -1095 +561 @@ -3005,7 +2940,7 @@ 225 226 -4 +2 @@ -3021,7 +2956,7 @@ 7 8 -4 +2 @@ -3035,9 +2970,9 @@ 12 -1134 -1135 -4 +1142 +1143 +2 @@ -3053,7 +2988,7 @@ 225 226 -34 +17 @@ -3069,7 +3004,7 @@ 1 2 -34 +17 @@ -3083,29 +3018,24 @@ 12 -159 -160 -4 +158 +159 +2 161 162 -4 +2 -176 -177 -4 - - -179 -180 -4 +174 +175 +5 225 226 -14 +7 @@ -3121,22 +3051,22 @@ 1 2 -4378 +2243 2 3 -569 +353 3 -5 -472 +6 +248 -5 -10 -102 +6 +9 +17 @@ -3152,7 +3082,7 @@ 1 2 -5523 +2862 @@ -3168,17 +3098,17 @@ 1 2 -4607 +2436 2 3 -784 +353 3 5 -131 +72 @@ -4421,11 +4351,11 @@ extractor_messages -7611 +750 id -7611 +750 severity @@ -4441,15 +4371,15 @@ entity -5273 +541 location -6681 +622 stack_trace -295 +121 @@ -4463,7 +4393,7 @@ 1 2 -7611 +750 @@ -4479,7 +4409,7 @@ 1 2 -7611 +750 @@ -4495,7 +4425,7 @@ 1 2 -7611 +750 @@ -4511,7 +4441,7 @@ 1 2 -7611 +750 @@ -4527,7 +4457,7 @@ 1 2 -7611 +750 @@ -4543,7 +4473,7 @@ 1 2 -7611 +750 @@ -4567,8 +4497,8 @@ 1 -7582 -7583 +721 +722 1 @@ -4630,8 +4560,8 @@ 1 -5267 -5268 +535 +536 1 @@ -4656,8 +4586,8 @@ 1 -6669 -6670 +610 +611 1 @@ -4677,8 +4607,8 @@ 2 -294 -295 +120 +121 1 @@ -4693,8 +4623,8 @@ 12 -7611 -7612 +750 +751 1 @@ -4741,8 +4671,8 @@ 12 -5273 -5274 +541 +542 1 @@ -4757,8 +4687,8 @@ 12 -6681 -6682 +622 +623 1 @@ -4773,8 +4703,8 @@ 12 -295 -296 +121 +122 1 @@ -4789,8 +4719,13 @@ 12 -1 -2 +2 +3 +1 + + +3 +4 1 @@ -4799,8 +4734,13 @@ 1 -11 -12 +16 +17 +1 + + +19 +20 1 @@ -4809,33 +4749,23 @@ 2 -38 -39 +30 +31 1 -104 -105 +49 +50 1 -216 -217 +244 +245 1 -326 -327 -1 - - -2411 -2412 -1 - - -4451 -4452 +334 +335 1 @@ -4887,11 +4817,21 @@ 3 +3 +4 +1 + + 5 6 1 +8 +9 +1 + + 11 12 1 @@ -4902,28 +4842,18 @@ 1 -47 -48 +20 +21 1 -51 -52 +189 +190 1 -275 -276 -1 - - -1647 -1648 -1 - - -3224 -3225 +284 +285 1 @@ -4943,8 +4873,13 @@ 3 -11 -12 +3 +4 +1 + + +8 +9 1 @@ -4958,28 +4893,23 @@ 1 -104 -105 +26 +27 1 -113 -114 +30 +31 1 -326 -327 +216 +217 1 -2017 -2018 -1 - - -4077 -4078 +306 +307 1 @@ -4996,11 +4926,11 @@ 1 2 -5 +6 -2 -3 +3 +4 1 @@ -5009,18 +4939,13 @@ 2 -11 -12 +34 +35 1 -77 -78 -1 - - -193 -194 +71 +72 1 @@ -5037,17 +4962,17 @@ 1 2 -4192 +425 2 3 -792 +92 3 -133 -289 +25 +24 @@ -5063,7 +4988,7 @@ 1 2 -5273 +541 @@ -5079,7 +5004,7 @@ 1 2 -5273 +541 @@ -5095,12 +5020,12 @@ 1 2 -5264 +540 2 3 -9 +1 @@ -5116,17 +5041,17 @@ 1 2 -4589 +490 2 -3 -478 +4 +47 -3 -67 -206 +4 +17 +4 @@ -5142,12 +5067,12 @@ 1 2 -5074 +512 2 -8 -199 +6 +29 @@ -5163,12 +5088,12 @@ 1 2 -5778 +521 2 3 -902 +100 29 @@ -5189,7 +5114,7 @@ 1 2 -6680 +621 2 @@ -5210,7 +5135,7 @@ 1 2 -6681 +622 @@ -5226,7 +5151,7 @@ 1 2 -6680 +621 2 @@ -5247,7 +5172,7 @@ 1 2 -6680 +621 2 @@ -5268,12 +5193,12 @@ 1 2 -6509 +596 2 3 -172 +26 @@ -5289,47 +5214,42 @@ 1 2 -92 +42 2 3 -42 +22 3 4 -21 +9 4 5 -22 +11 5 -7 -23 +6 +6 -7 -11 -27 +6 +9 +11 -11 -29 -24 +9 +21 +10 -29 -73 -23 - - -77 -726 -21 +21 +76 +10 @@ -5345,7 +5265,7 @@ 1 2 -294 +120 2 @@ -5366,7 +5286,7 @@ 1 2 -295 +121 @@ -5382,7 +5302,7 @@ 1 2 -294 +120 2 @@ -5403,47 +5323,42 @@ 1 2 -107 +55 2 3 -41 +17 3 4 -27 +10 4 5 -16 +8 5 -7 -24 +6 +6 -7 -12 -25 +6 +9 +11 -12 -33 -23 +9 +21 +10 -34 -114 -23 - - -195 -584 -9 +25 +76 +4 @@ -5459,47 +5374,42 @@ 1 2 -99 +50 2 3 -40 +18 3 4 -26 +8 4 5 -20 +10 5 -8 -27 +6 +6 -8 -13 -24 +6 +9 +11 -13 -37 -23 +9 +19 +10 -37 -111 -23 - - -115 -726 -13 +20 +76 +8 @@ -5509,19 +5419,19 @@ compilation_finished -1095 +564 id -1095 +564 cpu_seconds -944 +501 elapsed_seconds -1095 +564 @@ -5535,7 +5445,7 @@ 1 2 -1095 +564 @@ -5551,7 +5461,7 @@ 1 2 -1095 +564 @@ -5567,17 +5477,17 @@ 1 2 -808 +448 2 3 -126 +47 3 -5 -9 +6 +5 @@ -5593,17 +5503,17 @@ 1 2 -808 +448 2 3 -126 +47 3 -5 -9 +6 +5 @@ -5619,7 +5529,7 @@ 1 2 -1095 +564 @@ -5635,7 +5545,7 @@ 1 2 -1095 +564 @@ -5645,15 +5555,15 @@ compilation_assembly -1095 +564 id -1095 +564 assembly -1095 +564 @@ -5667,7 +5577,7 @@ 1 2 -1095 +564 @@ -5683,7 +5593,7 @@ 1 2 -1095 +564 @@ -6107,23 +6017,23 @@ externalData -58 +30 id -29 +15 path -4 +2 column -9 +5 value -58 +30 @@ -6137,7 +6047,7 @@ 1 2 -29 +15 @@ -6153,7 +6063,7 @@ 2 3 -29 +15 @@ -6169,7 +6079,7 @@ 2 3 -29 +15 @@ -6185,7 +6095,7 @@ 6 7 -4 +2 @@ -6201,7 +6111,7 @@ 2 3 -4 +2 @@ -6217,7 +6127,7 @@ 12 13 -4 +2 @@ -6233,7 +6143,7 @@ 6 7 -9 +5 @@ -6249,7 +6159,7 @@ 1 2 -9 +5 @@ -6265,7 +6175,7 @@ 6 7 -9 +5 @@ -6281,7 +6191,7 @@ 1 2 -58 +30 @@ -6297,7 +6207,7 @@ 1 2 -58 +30 @@ -6313,7 +6223,7 @@ 1 2 -58 +30 @@ -6323,41 +6233,41 @@ snapshotDate -4 +2 snapshotDate -4 +2 sourceLocationPrefix -4 +2 prefix -4 +2 duplicateCode -22736 +11701 id -22736 +11701 relativePath -3803 +1957 equivClass -7008 +3607 @@ -6371,7 +6281,7 @@ 1 2 -22736 +11701 @@ -6387,7 +6297,7 @@ 1 2 -22736 +11701 @@ -6403,52 +6313,52 @@ 1 2 -1061 +546 2 3 -564 +290 3 4 -423 +218 4 5 -219 +112 5 6 -219 +112 6 8 -336 +172 8 10 -277 +142 10 14 -316 +162 14 28 -287 +147 29 77 -97 +50 @@ -6464,52 +6374,52 @@ 1 2 -1129 +581 2 3 -521 +268 3 4 -443 +228 4 5 -233 +120 5 6 -228 +117 6 8 -326 +167 8 10 -277 +142 10 14 -311 +160 14 32 -292 +150 33 45 -38 +20 @@ -6525,32 +6435,32 @@ 2 3 -3765 +1937 3 4 -1144 +589 4 5 -784 +403 5 6 -428 +220 6 8 -569 +293 8 11 -316 +162 @@ -6566,37 +6476,37 @@ 1 2 -677 +348 2 3 -3438 +1769 3 4 -1076 +554 4 5 -677 +348 5 6 -384 +198 6 9 -579 +298 9 11 -175 +90 @@ -8674,31 +8584,31 @@ locations_default -14071994 +11326677 id -14071994 +11326677 file -6231 +6232 beginLine -164761 +157416 beginColumn -1456 +1453 endLine -177711 +175851 endColumn -1641 +1620 @@ -8712,7 +8622,7 @@ 1 2 -14071994 +11326677 @@ -8728,7 +8638,7 @@ 1 2 -14071994 +11326677 @@ -8744,7 +8654,7 @@ 1 2 -14071994 +11326677 @@ -8760,7 +8670,7 @@ 1 2 -14071994 +11326677 @@ -8776,7 +8686,7 @@ 1 2 -14071994 +11326677 @@ -8791,73 +8701,73 @@ 1 -19 -483 +5 +420 -19 -34 -472 +5 +7 +419 -34 -50 -491 +7 +9 +444 -50 -74 -470 +9 +12 +461 -74 -106 -471 +12 +17 +496 -106 -150 -478 +17 +28 +488 -150 -208 -471 +28 +45 +515 -208 -296 -468 +45 +76 +474 -296 -445 -468 - - -445 -685 +76 +129 469 -685 -1200 +129 +218 468 -1200 -2633 +218 +424 468 -2635 -42820 -494 +424 +1086 +468 -43085 +1087 +28809 +468 + + +31722 474768 -60 +174 @@ -8872,68 +8782,68 @@ 1 -12 -576 +5 +569 -12 +5 +7 +499 + + +7 +9 +447 + + +9 +11 +392 + + +11 +14 +504 + + +14 19 -508 +521 19 -27 -518 +28 +533 -27 -35 -476 +28 +40 +488 -35 -46 -515 +40 +60 +480 -46 -62 -498 +60 +94 +475 -62 -82 -478 - - -82 -114 -470 - - -114 -168 -471 - - -168 -273 -468 - - -273 -504 -479 - - -504 -1747 +94 +205 469 -1749 +205 +658 +468 + + +662 143014 -305 +387 @@ -8948,68 +8858,68 @@ 1 -7 -563 +3 +143 -7 +3 +4 +606 + + +4 +5 +675 + + +5 +6 +461 + + +6 +8 +533 + + +8 13 -499 +535 13 -19 -491 +20 +535 -19 -26 -481 +20 +30 +486 -26 -34 -517 - - -34 +30 43 -498 +500 43 -53 -482 - - -53 -64 -482 - - -64 -76 +59 479 -76 -91 +59 +82 474 -91 -112 -476 +82 +127 +469 -112 -166 -473 - - -166 +127 930 -316 +336 @@ -9024,73 +8934,68 @@ 1 +5 +561 + + +5 +7 +504 + + +7 +9 +449 + + +9 12 -515 +546 12 -18 -483 +16 +573 -18 -25 -470 +16 +22 +499 -25 -34 -492 +22 +33 +489 -34 -44 +33 +46 +489 + + +46 +73 +484 + + +73 +129 +487 + + +129 +326 468 -44 -56 -477 - - -56 -76 +326 +2738 468 -76 -104 -470 - - -104 -146 -471 - - -146 -231 -469 - - -231 -411 -469 - - -411 -884 -468 - - -888 -46288 -508 - - -55259 +2749 171760 -3 +215 @@ -9105,68 +9010,68 @@ 1 -15 -487 +5 +442 -15 +5 +7 +534 + + +7 +9 +416 + + +9 +12 +536 + + +12 +16 +469 + + +16 23 -477 +499 23 -32 -472 +34 +498 -32 -43 -509 - - -43 -54 -528 - - -54 -66 -488 - - -66 -77 +34 +48 470 -77 -91 -480 - - -91 -105 -492 - - -105 -123 +48 +64 482 -123 -148 -470 +64 +82 +475 -148 -186 -471 +82 +109 +472 -186 +109 +161 +485 + + +161 1038 -405 +454 @@ -9182,62 +9087,57 @@ 1 2 -4162 +2678 2 3 -30683 +41791 3 4 -15895 +15680 4 5 -16240 +16871 5 6 -9901 +8775 6 -8 -13419 +9 +12511 -8 -13 -13922 +9 +99 +11909 -13 -101 -14156 +99 +109 +11941 -101 -117 -12388 +109 +164 +11942 -117 -182 -12566 +164 +250 +11862 -182 -301 -12379 - - -301 -10779 -9050 +250 +7392 +11456 @@ -9253,37 +9153,42 @@ 1 2 -72393 +92520 2 -3 -30311 +18 +11816 -3 -38 -12530 +18 +50 +6689 -38 -52 -14355 +50 +51 +10035 -52 -78 -12367 +51 +65 +12205 -78 -118 -12665 +65 +105 +12183 -118 -6164 -10140 +105 +708 +11807 + + +709 +5267 +161 @@ -9299,57 +9204,52 @@ 1 2 -23472 +28742 2 3 -30017 +36135 3 4 -11007 +6197 4 5 -22184 +27310 5 6 -10198 +6023 6 7 -11742 +11735 7 -9 -13753 - - -9 -12 +10 13098 -12 -19 -12775 +10 +16 +12302 -19 -66 -12384 +16 +48 +11897 -66 -352 -4131 +48 +335 +3977 @@ -9365,32 +9265,27 @@ 1 2 -67387 +72276 2 3 -51814 +48541 3 4 -18655 +14456 4 6 -13945 +12667 6 -35 -12405 - - -35 306 -555 +9476 @@ -9406,62 +9301,57 @@ 1 2 -4192 +2731 2 3 -31626 +43580 3 4 -16669 +16640 4 5 -18712 +20845 5 6 -12090 +11859 6 7 -10186 +9405 7 9 -14627 +11941 9 -12 -14502 +14 +13283 -12 -17 -13374 +14 +24 +12004 -17 -29 -12449 +24 +94 +11811 -29 -111 -12415 - - -111 -389 -3919 +94 +378 +3317 @@ -9477,22 +9367,22 @@ 1 2 -352 +351 2 3 -184 +185 3 4 -101 +100 4 6 -129 +128 6 @@ -9501,33 +9391,33 @@ 13 -40 -111 +39 +109 -40 -110 -111 +39 +106 +109 -112 -476 -110 +106 +392 +109 -490 -5416 -110 +400 +3801 +109 -5448 -74978 -110 +4033 +35252 +109 -76214 -2221217 -24 +37256 +1800792 +30 @@ -9543,17 +9433,17 @@ 1 2 -482 +481 2 3 -187 +188 3 4 -115 +113 4 @@ -9563,31 +9453,31 @@ 6 11 -115 +117 11 -58 +59 110 -58 -194 -110 +59 +177 +109 -195 -1097 -110 +177 +695 +109 -1112 -3851 -110 +698 +2521 +109 -3881 -6230 +2548 +6053 8 @@ -9614,12 +9504,12 @@ 3 4 -114 +112 4 7 -110 +109 7 @@ -9628,28 +9518,28 @@ 18 -54 -113 +53 +111 -54 -139 -110 +53 +128 +109 -140 -803 -110 +128 +585 +109 -804 -6771 -110 +602 +4407 +109 -6786 +4493 116262 -79 +84 @@ -9675,12 +9565,12 @@ 3 4 -114 +112 4 7 -110 +109 7 @@ -9689,28 +9579,28 @@ 18 -54 -113 +53 +111 -54 -139 -110 +53 +129 +109 -140 -797 -110 +129 +586 +109 -803 -6771 -110 +603 +4408 +109 -6783 -124736 -79 +4493 +124735 +84 @@ -9726,17 +9616,17 @@ 1 2 -423 +422 2 3 -229 +230 3 4 -96 +93 4 @@ -9750,28 +9640,28 @@ 12 -25 -114 +24 +112 -25 -53 +24 +48 110 -53 -108 -111 +48 +103 +109 -108 -204 -111 +103 +176 +110 -204 -727 -38 +176 +724 +43 @@ -9787,62 +9677,57 @@ 1 2 -30737 +43052 2 3 -14516 +15495 3 4 -16816 +16141 4 5 -12515 +11843 5 -6 -10358 +7 +15117 -6 -9 -14908 - - -9 +7 51 -14736 +13292 51 -64 -13405 +67 +13277 -64 -109 -13432 +67 +108 +13666 -109 +108 170 -13423 +13281 170 -277 -13376 +273 +13192 -277 -10684 -9489 +273 +6927 +7495 @@ -9858,37 +9743,37 @@ 1 2 -74588 +102373 2 -3 -32294 +50 +10686 -3 +50 51 -15349 +14316 51 -53 -14844 +61 +13298 -53 -91 -13581 +61 +105 +13198 -91 -136 -14119 +105 +140 +13318 -136 -5697 -12936 +140 +5438 +8662 @@ -9904,27 +9789,27 @@ 1 2 -94269 +108963 2 3 -38081 +30801 3 4 -18056 +14008 4 -6 -14158 +7 +15017 -6 -61 -13147 +7 +50 +7062 @@ -9940,57 +9825,52 @@ 1 2 -31574 +44241 2 3 -28818 +33451 3 4 -12788 +9654 4 5 -19691 +22023 5 6 -11851 +9633 6 7 -11679 +10956 7 -9 -15127 +10 +15510 -9 -12 -14463 +10 +16 +13744 -12 -18 -13365 +16 +55 +13266 -18 -58 -13379 - - -58 -353 -4976 +55 +334 +3373 @@ -10006,62 +9886,57 @@ 1 2 -31277 +43633 2 3 -18344 +19238 3 4 -19309 +20512 4 5 -15250 +15969 5 6 -13461 +14483 6 7 -9784 +8953 7 9 -14539 +12318 9 -12 -13944 +14 +13943 -12 -17 -13345 +14 +27 +13475 -17 -32 -13515 +27 +206 +13190 -32 -156 -13332 - - -156 -388 -1611 +206 +378 +137 @@ -10077,12 +9952,12 @@ 1 2 -406 +393 2 3 -205 +202 3 @@ -10092,42 +9967,42 @@ 4 7 -126 +122 7 51 -124 +123 51 -122 -126 - - -122 -325 +121 124 -328 -1118 -124 +121 +301 +122 -1126 -9599 -124 +311 +1031 +122 -9617 -82632 -124 +1037 +6674 +122 -82675 -908062 -42 +6754 +56985 +122 + + +57295 +866412 +52 @@ -10143,52 +10018,52 @@ 1 2 -521 +507 2 3 -186 +182 3 4 -119 +120 4 9 -130 - - -9 -62 -132 - - -62 -128 127 -129 -222 -124 +9 +61 +125 -222 -710 -124 +61 +124 +123 -716 -3687 -124 +124 +205 +122 -3691 -5367 -54 +206 +441 +122 + + +441 +1921 +122 + + +1944 +4225 +70 @@ -10204,12 +10079,12 @@ 1 2 -414 +400 2 3 -211 +209 3 @@ -10219,42 +10094,42 @@ 4 6 -127 +123 6 14 -131 +130 14 -44 -125 +43 +123 -44 -124 -124 +43 +120 +123 -126 -541 -124 +121 +466 +122 -549 -5838 -124 +471 +4055 +122 -6139 -19147 -124 +4055 +13772 +122 -19459 -47830 -14 +13909 +47532 +23 @@ -10270,22 +10145,22 @@ 1 2 -518 +502 2 3 -232 +231 3 4 -96 +95 4 7 -147 +146 7 @@ -10294,28 +10169,28 @@ 16 -34 -124 - - -34 -83 -128 - - -83 -114 -125 - - -114 -164 +33 127 -164 -338 -11 +33 +78 +122 + + +78 +107 +122 + + +107 +151 +124 + + +151 +337 +18 @@ -10331,7 +10206,7 @@ 1 2 -416 +400 2 @@ -10346,42 +10221,95 @@ 4 6 -127 +123 6 14 -131 +130 14 -44 -125 +43 +123 -44 -124 -124 +43 +120 +123 -126 -537 -124 +121 +466 +122 -541 -5829 -124 +475 +4050 +122 -6123 -19057 -124 +4064 +13686 +122 -19443 -47820 -14 +13833 +47528 +23 + + + + + + + + +locations_mapped +248620 + + +id +248620 + + +mapped_to +211461 + + + + +id +mapped_to + + +12 + + +1 +2 +248620 + + + + + + +mapped_to +id + + +12 + + +1 +2 +205510 + + +2 +119 +5951 @@ -10391,23 +10319,23 @@ numlines -4585662 +4532217 element_id -4585655 +4532216 num_lines -1354 +1349 num_code -1247 +1242 num_comment -637 +635 @@ -10421,12 +10349,12 @@ 1 2 -4585648 +4532215 2 3 -7 +1 @@ -10442,12 +10370,12 @@ 1 2 -4585648 +4532215 2 3 -7 +1 @@ -10463,12 +10391,7 @@ 1 2 -4585651 - - -2 -3 -4 +4532216 @@ -10484,37 +10407,37 @@ 1 2 -651 +660 2 3 -207 +208 3 4 -97 +94 4 -7 -125 +6 +94 -7 -19 -105 +6 +12 +108 -19 -121 -102 +12 +50 +104 -126 -1600586 -67 +52 +1598592 +81 @@ -10530,37 +10453,32 @@ 1 2 -723 +733 2 3 -194 +198 3 4 -106 +99 4 7 -111 +121 7 -16 -103 +15 +102 -16 -35 -104 - - -35 -39 -13 +15 +34 +96 @@ -10576,37 +10494,32 @@ 1 2 -723 +733 2 3 -196 +198 3 4 -102 +97 4 7 -105 +118 7 17 -104 +109 17 -32 -106 - - -32 81 -18 +94 @@ -10622,37 +10535,37 @@ 1 2 -647 +651 2 3 -152 +149 3 4 -79 +83 4 6 -93 +99 6 14 -98 +102 14 -50 -95 +77 +94 -52 -1614463 -83 +83 +1607845 +64 @@ -10668,37 +10581,32 @@ 1 2 -723 +728 2 3 -143 +140 3 4 -82 +84 4 7 -100 +107 7 -19 +18 96 -19 -43 -94 - - -43 -49 -9 +18 +42 +87 @@ -10714,37 +10622,32 @@ 1 2 -723 +728 2 3 -145 +141 3 4 -77 +80 4 7 -102 +106 7 -16 -95 - - -16 -50 +15 94 -50 -85 -11 +15 +83 +93 @@ -10765,12 +10668,12 @@ 2 3 -131 +134 3 4 -56 +55 4 @@ -10780,17 +10683,17 @@ 6 14 -49 +50 14 -173 +178 48 -215 -4549173 -19 +178 +4511467 +14 @@ -10811,32 +10714,32 @@ 2 3 -135 +138 3 4 -57 +56 4 6 -51 +50 6 -16 +15 49 -16 -128 -48 +15 +119 +49 -136 -746 -12 +131 +738 +8 @@ -10857,32 +10760,32 @@ 2 3 -135 +139 3 4 -56 +54 4 6 -53 +51 6 -16 +15 48 -16 -117 -48 +15 +103 +49 -118 -739 -12 +116 +731 +9 @@ -10892,27 +10795,27 @@ assemblies -4198 +2160 id -4198 +2160 file -4198 +2160 fullname -3438 +1769 name -3170 +1631 version -370 +190 @@ -10926,7 +10829,7 @@ 1 2 -4198 +2160 @@ -10942,7 +10845,7 @@ 1 2 -4198 +2160 @@ -10958,7 +10861,7 @@ 1 2 -4198 +2160 @@ -10974,7 +10877,7 @@ 1 2 -4198 +2160 @@ -10990,7 +10893,7 @@ 1 2 -4198 +2160 @@ -11006,7 +10909,7 @@ 1 2 -4198 +2160 @@ -11022,7 +10925,7 @@ 1 2 -4198 +2160 @@ -11038,7 +10941,7 @@ 1 2 -4198 +2160 @@ -11054,12 +10957,12 @@ 1 2 -2678 +1378 2 3 -759 +391 @@ -11075,12 +10978,12 @@ 1 2 -2678 +1378 2 3 -759 +391 @@ -11096,7 +10999,7 @@ 1 2 -3438 +1769 @@ -11112,7 +11015,7 @@ 1 2 -3438 +1769 @@ -11128,17 +11031,17 @@ 1 2 -2186 +1125 2 3 -940 +483 3 4 -43 +22 @@ -11154,17 +11057,17 @@ 1 2 -2186 +1125 2 3 -940 +483 3 4 -43 +22 @@ -11180,12 +11083,12 @@ 1 2 -2946 +1516 2 4 -224 +115 @@ -11201,12 +11104,12 @@ 1 2 -2946 +1516 2 4 -224 +115 @@ -11222,32 +11125,32 @@ 1 2 -204 +105 2 3 -53 +27 3 6 -29 +15 6 10 -34 +17 11 37 -29 +15 50 386 -19 +10 @@ -11263,32 +11166,32 @@ 1 2 -204 +105 2 3 -53 +27 3 6 -29 +15 6 10 -34 +17 11 37 -29 +15 50 386 -19 +10 @@ -11304,32 +11207,32 @@ 1 2 -209 +107 2 3 -53 +27 3 5 -24 +12 6 10 -34 +17 11 36 -29 +15 50 234 -19 +10 @@ -11345,32 +11248,32 @@ 1 2 -209 +107 2 3 -53 +27 3 5 -24 +12 6 10 -34 +17 11 36 -29 +15 50 234 -19 +10 @@ -11380,27 +11283,27 @@ files -42467 +24351 id -42467 +24351 name -42467 +24351 simple -22935 +13679 ext -38 +22 fromSource -4 +2 @@ -11414,7 +11317,7 @@ 1 2 -42467 +24351 @@ -11430,7 +11333,7 @@ 1 2 -42467 +24351 @@ -11446,7 +11349,7 @@ 1 2 -42467 +24351 @@ -11462,7 +11365,7 @@ 1 2 -42467 +24351 @@ -11478,7 +11381,7 @@ 1 2 -42467 +24351 @@ -11494,7 +11397,7 @@ 1 2 -42467 +24351 @@ -11510,7 +11413,7 @@ 1 2 -42467 +24351 @@ -11526,7 +11429,7 @@ 1 2 -42467 +24351 @@ -11542,12 +11445,12 @@ 1 2 -21528 +12787 2 154 -1407 +892 @@ -11563,12 +11466,12 @@ 1 2 -21528 +12787 2 154 -1407 +892 @@ -11584,12 +11487,12 @@ 1 2 -22146 +13168 2 5 -789 +511 @@ -11605,7 +11508,7 @@ 1 2 -22935 +13679 @@ -11621,42 +11524,47 @@ 1 2 -4 +2 2 3 -4 +2 6 7 -4 +2 166 167 -4 +2 173 174 -4 +2 861 862 -4 +2 + + +995 +996 +2 2875 2876 -4 +2 4635 4636 -4 +2 @@ -11672,42 +11580,47 @@ 1 2 -4 +2 2 3 -4 +2 6 7 -4 +2 166 167 -4 +2 173 174 -4 +2 861 862 -4 +2 + + +995 +996 +2 2875 2876 -4 +2 4635 4636 -4 +2 @@ -11723,37 +11636,42 @@ 1 2 -4 +2 2 3 -9 +5 166 167 -4 +2 169 170 -4 +2 214 215 -4 +2 650 651 -4 +2 + + +790 +791 +2 3818 3819 -4 +2 @@ -11769,7 +11687,7 @@ 1 2 -38 +22 @@ -11783,9 +11701,9 @@ 12 -8719 -8720 -4 +9714 +9715 +2 @@ -11799,9 +11717,9 @@ 12 -8719 -8720 -4 +9714 +9715 +2 @@ -11815,9 +11733,9 @@ 12 -4709 -4710 -4 +5457 +5458 +2 @@ -11831,9 +11749,9 @@ 12 -8 -9 -4 +9 +10 +2 @@ -11843,19 +11761,19 @@ folders -16940 +9177 id -16940 +9177 name -14723 +8036 simple -2776 +1428 @@ -11869,7 +11787,7 @@ 1 2 -16940 +9177 @@ -11885,7 +11803,7 @@ 1 2 -16940 +9177 @@ -11901,7 +11819,7 @@ 1 2 -14723 +8036 @@ -11917,12 +11835,12 @@ 1 2 -12507 +6896 2 3 -2216 +1140 @@ -11938,27 +11856,27 @@ 1 2 -1821 +842 2 3 -375 +278 3 4 -204 +107 4 -11 -209 +10 +107 -11 +10 383 -165 +92 @@ -11974,27 +11892,27 @@ 1 2 -1821 +842 2 3 -375 +278 3 4 -204 +107 4 -11 -209 +10 +107 -11 +10 383 -165 +92 @@ -12004,15 +11922,15 @@ containerparent -57181 +32383 parent -14723 +8036 child -57181 +32383 @@ -12026,37 +11944,37 @@ 1 2 -8255 +4356 2 3 -1938 +1070 3 4 -769 +486 4 5 -969 +541 5 9 -1105 +629 9 -18 -1139 +17 +609 -18 +17 170 -545 +343 @@ -12072,7 +11990,7 @@ 1 2 -57181 +32383 @@ -12082,15 +12000,15 @@ file_extraction_mode -26778 +16276 file -26778 +16276 mode -4 +2 @@ -12104,7 +12022,7 @@ 1 2 -26778 +16276 @@ -12118,9 +12036,9 @@ 12 -5498 -5499 -4 +6493 +6494 +2 @@ -12130,15 +12048,15 @@ namespaces -21942 +11293 id -21942 +11293 name -4890 +2516 @@ -12152,7 +12070,7 @@ 1 2 -21942 +11293 @@ -12168,37 +12086,37 @@ 1 2 -14 +7 2 3 -3492 +1797 3 4 -4 +2 4 5 -623 +320 6 10 -370 +190 10 101 -370 +190 110 139 -14 +7 @@ -12208,15 +12126,15 @@ namespace_declarations -19760 +8355 id -19760 +8355 namespace_id -3886 +1774 @@ -12230,7 +12148,7 @@ 1 2 -19760 +8355 @@ -12246,42 +12164,37 @@ 1 2 -1397 +669 2 3 -798 +406 3 4 -414 +175 4 5 -306 +140 5 6 -224 +110 6 9 -331 +140 9 -17 -301 - - -17 996 -112 +132 @@ -12291,15 +12204,15 @@ namespace_declaration_location -19760 +8355 id -19760 +8355 loc -19760 +8355 @@ -12313,7 +12226,7 @@ 1 2 -19760 +8355 @@ -12329,7 +12242,7 @@ 1 2 -19760 +8355 @@ -12339,15 +12252,15 @@ parent_namespace -777067 +388662 child_id -777067 +388662 namespace_id -13554 +6974 @@ -12361,7 +12274,7 @@ 1 2 -777067 +388662 @@ -12377,57 +12290,57 @@ 1 2 -3326 +1709 2 3 -1626 +842 3 4 -1027 +531 4 5 -915 +468 5 7 -1251 +641 7 10 -1091 +561 10 15 -1139 +589 15 23 -1061 +546 23 51 -1027 +523 51 835 -1017 +523 900 -35556 -68 +34743 +35 @@ -12437,15 +12350,15 @@ parent_namespace_declaration -88304 +43445 child_id -87788 +43212 namespace_id -19760 +8355 @@ -12459,12 +12372,12 @@ 1 2 -87637 +43145 2 60 -150 +67 @@ -12480,32 +12393,32 @@ 1 2 -13779 +5412 2 9 -1714 +747 9 13 -1276 +656 13 16 -1427 +734 16 -32 -1509 +21 +508 -32 +31 33 -53 +295 @@ -12515,15 +12428,15 @@ using_namespace_directives -144253 +66100 id -144253 +66100 namespace_id -4227 +1990 @@ -12537,7 +12450,7 @@ 1 2 -144253 +66100 @@ -12553,52 +12466,47 @@ 1 2 -1495 +696 2 3 -472 +285 3 4 -297 +115 4 -5 -238 +6 +182 -5 -8 -365 +6 +11 +177 -8 -14 -336 +11 +21 +177 -14 -25 -321 +21 +45 +152 -25 -63 -326 +48 +206 +150 -64 -465 -321 - - -510 -2519 -53 +214 +2199 +50 @@ -12608,15 +12516,15 @@ using_static_directives -390 +199 id -390 +199 type_id -54 +32 @@ -12630,7 +12538,7 @@ 1 2 -390 +199 @@ -12646,46 +12554,46 @@ 1 2 -2 +4 2 3 -22 +15 3 4 -4 +1 4 5 -5 +3 5 -6 +7 2 -6 -7 -5 - - -8 +7 9 -7 +2 -12 +16 +23 +2 + + +26 +27 +1 + + +30 31 -5 - - -46 -71 2 @@ -12696,15 +12604,15 @@ using_directive_location -144312 +74275 id -144312 +74275 loc -144268 +74252 @@ -12718,7 +12626,7 @@ 1 2 -144312 +74275 @@ -12734,12 +12642,2175 @@ 1 2 -144224 +74229 2 3 -43 +22 + + + + + + + + +directive_ifs +2550 + + +id +2550 + + +branchTaken +2 + + +conditionValue +2 + + + + +id +branchTaken + + +12 + + +1 +2 +2550 + + + + + + +id +conditionValue + + +12 + + +1 +2 +2550 + + + + + + +branchTaken +id + + +12 + + +1194 +1195 +1 + + +1219 +1220 +1 + + + + + + +branchTaken +conditionValue + + +12 + + +1 +2 +1 + + +2 +3 +1 + + + + + + +conditionValue +id + + +12 + + +1199 +1200 +1 + + +1214 +1215 +1 + + + + + + +conditionValue +branchTaken + + +12 + + +1 +2 +1 + + +2 +3 +1 + + + + + + + + +directive_elifs +7 + + +id +7 + + +branchTaken +1 + + +conditionValue +2 + + +parent +7 + + +index +1 + + + + +id +branchTaken + + +12 + + +1 +2 +7 + + + + + + +id +conditionValue + + +12 + + +1 +2 +7 + + + + + + +id +parent + + +12 + + +1 +2 +7 + + + + + + +id +index + + +12 + + +1 +2 +7 + + + + + + +branchTaken +id + + +12 + + +7 +8 +1 + + + + + + +branchTaken +conditionValue + + +12 + + +2 +3 +1 + + + + + + +branchTaken +parent + + +12 + + +7 +8 +1 + + + + + + +branchTaken +index + + +12 + + +1 +2 +1 + + + + + + +conditionValue +id + + +12 + + +1 +2 +1 + + +6 +7 +1 + + + + + + +conditionValue +branchTaken + + +12 + + +1 +2 +2 + + + + + + +conditionValue +parent + + +12 + + +1 +2 +1 + + +6 +7 +1 + + + + + + +conditionValue +index + + +12 + + +1 +2 +2 + + + + + + +parent +id + + +12 + + +1 +2 +7 + + + + + + +parent +branchTaken + + +12 + + +1 +2 +7 + + + + + + +parent +conditionValue + + +12 + + +1 +2 +7 + + + + + + +parent +index + + +12 + + +1 +2 +7 + + + + + + +index +id + + +12 + + +7 +8 +1 + + + + + + +index +branchTaken + + +12 + + +1 +2 +1 + + + + + + +index +conditionValue + + +12 + + +2 +3 +1 + + + + + + +index +parent + + +12 + + +7 +8 +1 + + + + + + + + +directive_elses +1140 + + +id +1140 + + +branchTaken +2 + + +parent +1140 + + +index +2 + + + + +id +branchTaken + + +12 + + +1 +2 +1140 + + + + + + +id +parent + + +12 + + +1 +2 +1140 + + + + + + +id +index + + +12 + + +1 +2 +1140 + + + + + + +branchTaken +id + + +12 + + +329 +330 +1 + + +750 +751 +1 + + + + + + +branchTaken +parent + + +12 + + +329 +330 +1 + + +750 +751 +1 + + + + + + +branchTaken +index + + +12 + + +2 +3 +2 + + + + + + +parent +id + + +12 + + +1 +2 +1140 + + + + + + +parent +branchTaken + + +12 + + +1 +2 +1140 + + + + + + +parent +index + + +12 + + +1 +2 +1140 + + + + + + +index +id + + +12 + + +7 +8 +1 + + +1072 +1073 +1 + + + + + + +index +branchTaken + + +12 + + +2 +3 +2 + + + + + + +index +parent + + +12 + + +7 +8 +1 + + +1072 +1073 +1 + + + + + + + + +directive_endifs +2550 + + +id +2550 + + +start +2550 + + + + +id +start + + +12 + + +1 +2 +2550 + + + + + + +start +id + + +12 + + +1 +2 +2550 + + + + + + + + +directive_define_symbols +3314 + + +id +3314 + + +name +86 + + + + +id +name + + +12 + + +1 +2 +3314 + + + + + + +name +id + + +12 + + +1 +2 +17 + + +2 +3 +8 + + +3 +4 +10 + + +4 +5 +8 + + +5 +6 +7 + + +6 +7 +5 + + +7 +12 +7 + + +13 +23 +6 + + +24 +55 +7 + + +97 +656 +7 + + + + + + + + +directive_regions +565 + + +id +565 + + +name +216 + + + + +id +name + + +12 + + +1 +2 +565 + + + + + + +name +id + + +12 + + +1 +2 +6 + + +2 +3 +175 + + +3 +4 +1 + + +4 +5 +26 + + +6 +31 +8 + + + + + + + + +directive_endregions +565 + + +id +565 + + +start +565 + + + + +id +start + + +12 + + +1 +2 +565 + + + + + + +start +id + + +12 + + +1 +2 +565 + + + + + + + + +directive_lines +128896 + + +id +128896 + + +kind +7 + + + + +id +kind + + +12 + + +1 +2 +128896 + + + + + + +kind +id + + +12 + + +16650 +16651 +5 + + +18118 +18119 +2 + + + + + + + + +directive_line_value +41738 + + +id +41738 + + +line +709 + + + + +id +line + + +12 + + +1 +2 +41738 + + + + + + +line +id + + +12 + + +1 +2 +147 + + +2 +3 +70 + + +3 +4 +55 + + +4 +7 +65 + + +7 +11 +60 + + +11 +15 +55 + + +15 +27 +62 + + +27 +46 +55 + + +46 +104 +55 + + +106 +549 +55 + + +569 +727 +27 + + + + + + + + +directive_line_file +41738 + + +id +41738 + + +file +2396 + + + + +id +file + + +12 + + +1 +2 +41738 + + + + + + +file +id + + +12 + + +1 +2 +308 + + +2 +3 +396 + + +3 +4 +255 + + +4 +6 +205 + + +6 +7 +110 + + +7 +9 +200 + + +9 +12 +180 + + +12 +16 +205 + + +16 +27 +185 + + +27 +42 +188 + + +42 +2665 +160 + + + + + + + + +directive_nullables +83477 + + +id +83477 + + +setting +5 + + +target +2 + + + + +id +setting + + +12 + + +1 +2 +83477 + + + + + + +id +target + + +12 + + +1 +2 +83477 + + + + + + +setting +id + + +12 + + +16650 +16651 +5 + + + + + + +setting +target + + +12 + + +1 +2 +5 + + + + + + +target +id + + +12 + + +33300 +33301 +2 + + + + + + +target +setting + + +12 + + +2 +3 +2 + + + + + + + + +directive_warnings +1 + + +id +1 + + +message +1 + + + + +id +message + + +12 + + +1 +2 +1 + + + + + + +message +id + + +12 + + +1 +2 +1 + + + + + + + + +directive_errors +1 + + +id +1 + + +message +1 + + + + +id +message + + +12 + + +1 +2 +1 + + + + + + +message +id + + +12 + + +1 +2 +1 + + + + + + + + +directive_undefines +1 + + +id +1 + + +name +1 + + + + +id +name + + +12 + + +1 +2 +1 + + + + + + +name +id + + +12 + + +1 +2 +1 + + + + + + + + +directive_defines +5 + + +id +5 + + +name +5 + + + + +id +name + + +12 + + +1 +2 +5 + + + + + + +name +id + + +12 + + +1 +2 +5 + + + + + + + + +pragma_checksums +2494 + + +id +2494 + + +file +2494 + + +guid +2 + + +bytes +2338 + + + + +id +file + + +12 + + +1 +2 +2494 + + + + + + +id +guid + + +12 + + +1 +2 +2494 + + + + + + +id +bytes + + +12 + + +1 +2 +2494 + + + + + + +file +id + + +12 + + +1 +2 +2494 + + + + + + +file +guid + + +12 + + +1 +2 +2494 + + + + + + +file +bytes + + +12 + + +1 +2 +2494 + + + + + + +guid +id + + +12 + + +995 +996 +2 + + + + + + +guid +file + + +12 + + +995 +996 +2 + + + + + + +guid +bytes + + +12 + + +933 +934 +2 + + + + + + +bytes +id + + +12 + + +1 +2 +2288 + + +2 +19 +50 + + + + + + +bytes +file + + +12 + + +1 +2 +2288 + + +2 +19 +50 + + + + + + +bytes +guid + + +12 + + +1 +2 +2338 + + + + + + + + +pragma_warnings +14725 + + +id +14725 + + +kind +5 + + + + +id +kind + + +12 + + +1 +2 +14725 + + + + + + +kind +id + + +12 + + +2937 +2938 +5 + + + + + + + + +pragma_warning_error_codes +14730 + + +id +14725 + + +errorCode +15 + + +index +5 + + + + +id +errorCode + + +12 + + +1 +2 +14720 + + +2 +3 +5 + + + + + + +id +index + + +12 + + +1 +2 +14720 + + +2 +3 +5 + + + + + + +errorCode +id + + +12 + + +2 +3 +5 + + +946 +947 +5 + + +1990 +1991 +5 + + + + + + +errorCode +index + + +12 + + +1 +2 +15 + + + + + + +index +id + + +12 + + +2 +3 +2 + + +5874 +5875 +2 + + + + + + +index +errorCode + + +12 + + +1 +2 +2 + + +5 +6 +2 + + + + + + + + +preprocessor_directive_location +229688 + + +id +229688 + + +loc +229688 + + + + +id +loc + + +12 + + +1 +2 +229688 + + + + + + +loc +id + + +12 + + +1 +2 +229688 + + + + + + + + +preprocessor_directive_compilation +229688 + + +id +229688 + + +compilation +172 + + + + +id +compilation + + +12 + + +1 +2 +229688 + + + + + + +compilation +id + + +12 + + +4 +11 +12 + + +16 +62 +15 + + +75 +144 +15 + + +149 +226 +15 + + +248 +317 +15 + + +342 +459 +15 + + +503 +665 +15 + + +772 +1090 +15 + + +1155 +1276 +15 + + +1343 +2001 +15 + + +2121 +4115 +15 + + +6086 +19444 +10 + + + + + + + + +preprocessor_directive_active +229688 + + +id +229688 + + +active +2 + + + + +id +active + + +12 + + +1 +2 +229688 + + + + + + +active +id + + +12 + + +91625 +91626 +2 @@ -12749,19 +14820,19 @@ types -867174 +434504 id -867174 +434504 kind -131 +67 name -366861 +184347 @@ -12775,7 +14846,7 @@ 1 2 -867174 +434504 @@ -12791,7 +14862,7 @@ 1 2 -867174 +434504 @@ -12807,32 +14878,32 @@ 1 2 -82 +42 45 -199 -9 +198 +5 -366 -1874 -9 +342 +1750 +5 -2454 -10198 -9 +2450 +9903 +5 -22085 -36570 -9 +20838 +35370 +5 -41596 -62642 -9 +40817 +61603 +5 @@ -12848,32 +14919,32 @@ 1 2 -82 +42 45 -158 -9 +154 +5 -169 +168 701 -9 +5 -1086 +1043 2228 -9 +5 -6598 -10563 -9 +6467 +9921 +5 -18339 -35727 -9 +17642 +35459 +5 @@ -12889,17 +14960,17 @@ 1 2 -324613 +163114 2 5 -28839 +14629 5 -6356 -13408 +6327 +6603 @@ -12915,12 +14986,12 @@ 1 2 -365424 +183613 2 4 -1436 +734 @@ -12930,15 +15001,15 @@ typerefs -234794 +120781 id -234794 +120781 name -176984 +91080 @@ -12952,7 +15023,7 @@ 1 2 -234794 +120781 @@ -12968,17 +15039,17 @@ 1 2 -162435 +83592 2 7 -13481 +6938 7 2183 -1066 +548 @@ -12988,15 +15059,15 @@ typeref_type -234613 +120694 id -234613 +120694 typeId -234613 +120694 @@ -13010,7 +15081,7 @@ 1 2 -234613 +120694 @@ -13026,7 +15097,7 @@ 1 2 -234613 +120694 @@ -13036,23 +15107,23 @@ array_element_type -9122 +4384 array -9122 +4384 dimension -9 +5 rank -9 +5 element -9112 +4379 @@ -13066,7 +15137,7 @@ 1 2 -9122 +4384 @@ -13082,7 +15153,7 @@ 1 2 -9122 +4384 @@ -13098,7 +15169,7 @@ 1 2 -9122 +4384 @@ -13114,12 +15185,12 @@ 20 21 -4 +2 -1853 -1854 -4 +1729 +1730 +2 @@ -13135,12 +15206,12 @@ 1 2 -4 +2 2 3 -4 +2 @@ -13156,12 +15227,12 @@ 20 21 -4 +2 -1851 -1852 -4 +1727 +1728 +2 @@ -13177,12 +15248,12 @@ 2 3 -4 +2 -1871 -1872 -4 +1747 +1748 +2 @@ -13198,12 +15269,12 @@ 1 2 -4 +2 2 3 -4 +2 @@ -13219,12 +15290,12 @@ 2 3 -4 +2 -1871 -1872 -4 +1747 +1748 +2 @@ -13240,12 +15311,12 @@ 1 2 -9103 +4374 2 3 -9 +5 @@ -13261,7 +15332,7 @@ 1 2 -9112 +4379 @@ -13277,12 +15348,12 @@ 1 2 -9103 +4374 2 3 -9 +5 @@ -13292,15 +15363,15 @@ nullable_underlying_type -979 +550 nullable -979 +550 underlying -979 +550 @@ -13314,7 +15385,7 @@ 1 2 -979 +550 @@ -13330,7 +15401,7 @@ 1 2 -979 +550 @@ -13340,15 +15411,15 @@ pointer_referent_type -219 +112 pointer -219 +112 referent -219 +112 @@ -13362,7 +15433,7 @@ 1 2 -219 +112 @@ -13378,7 +15449,7 @@ 1 2 -219 +112 @@ -13388,15 +15459,15 @@ enum_underlying_type -11952 +6141 enum_id -11952 +6141 underlying_type_id -38 +20 @@ -13410,7 +15481,7 @@ 1 2 -11952 +6141 @@ -13426,37 +15497,37 @@ 5 6 -9 +5 23 24 -4 +2 25 26 -4 +2 41 42 -4 +2 172 173 -4 +2 285 286 -4 +2 -1898 -1899 -4 +1894 +1895 +2 @@ -13466,15 +15537,15 @@ delegate_return_type -107553 +52229 delegate_id -107553 +52229 return_type_id -55510 +26697 @@ -13488,7 +15559,7 @@ 1 2 -107553 +52229 @@ -13504,12 +15575,12 @@ 1 2 -52198 +25171 2 -4178 -3312 +4000 +1526 @@ -13519,15 +15590,15 @@ function_pointer_return_type -11 +9 function_pointer_id -11 +9 return_type_id -3 +6 @@ -13541,7 +15612,7 @@ 1 2 -11 +9 @@ -13555,14 +15626,9 @@ 12 -2 -3 -1 - - -3 -4 -1 +1 +2 +5 4 @@ -13577,15 +15643,15 @@ extend -323488 +160600 sub -323488 +160600 super -31566 +16246 @@ -13599,7 +15665,7 @@ 1 2 -323488 +160600 @@ -13615,27 +15681,27 @@ 1 2 -22629 +11646 2 3 -3979 +2050 3 5 -2415 +1240 5 70 -2376 +1223 70 -22083 -165 +20836 +85 @@ -13645,26 +15711,26 @@ anonymous_types -1212 +571 id -1212 +571 implement -541717 +266554 sub -226353 +112586 super -122545 +60780 @@ -13678,27 +15744,27 @@ 1 2 -100773 +51182 2 3 -57044 +27933 3 4 -36110 +17643 4 7 -18971 +9373 7 21 -13452 +6455 @@ -13714,27 +15780,27 @@ 1 2 -66951 +33561 2 3 -29783 +14692 3 4 -10247 +4983 4 6 -8694 +4168 6 -21807 -6867 +20685 +3374 @@ -13744,15 +15810,15 @@ type_location -553694 +277271 id -466968 +237743 loc -29876 +12499 @@ -13766,17 +15832,17 @@ 1 2 -407390 +209975 2 3 -39233 +19400 3 638 -20344 +8367 @@ -13792,17 +15858,22 @@ 1 2 -26004 +10568 2 -26 -2269 +20 +962 -26 +20 +1759 +937 + + +1782 12195 -1602 +30 @@ -13812,15 +15883,15 @@ tuple_underlying_type -1782 +857 tuple -1782 +857 struct -1139 +574 @@ -13834,7 +15905,7 @@ 1 2 -1782 +857 @@ -13850,17 +15921,17 @@ 1 2 -642 +333 2 3 -423 +213 3 -9 -73 +6 +27 @@ -13870,19 +15941,19 @@ tuple_element -6789 +3374 tuple -1777 +854 index -102 +52 field -6789 +3374 @@ -13896,37 +15967,37 @@ 1 2 -43 +22 2 3 -1134 +523 3 4 -146 +75 4 5 -63 +32 5 7 -141 +72 7 13 -141 +72 13 22 -107 +55 @@ -13942,37 +16013,37 @@ 1 2 -43 +22 2 3 -1134 +523 3 4 -146 +75 4 5 -63 +32 5 7 -141 +72 7 13 -141 +72 13 22 -107 +55 @@ -13988,107 +16059,107 @@ 2 3 -4 +2 4 5 -4 +2 6 7 -4 +2 8 9 -4 +2 10 11 -4 +2 12 13 -4 +2 14 15 -4 +2 18 19 -4 +2 22 23 -4 +2 26 27 -4 +2 30 31 -4 +2 34 35 -4 +2 38 39 -4 +2 43 44 -4 +2 51 52 -4 +2 59 60 -4 +2 80 81 -4 +2 93 94 -4 +2 123 124 -4 +2 -356 -357 -4 +332 +333 +2 -365 -366 -4 +341 +342 +2 @@ -14104,107 +16175,107 @@ 2 3 -4 +2 4 5 -4 +2 6 7 -4 +2 8 9 -4 +2 10 11 -4 +2 12 13 -4 +2 14 15 -4 +2 18 19 -4 +2 22 23 -4 +2 26 27 -4 +2 30 31 -4 +2 34 35 -4 +2 38 39 -4 +2 43 44 -4 +2 51 52 -4 +2 59 60 -4 +2 80 81 -4 +2 93 94 -4 +2 123 124 -4 +2 -356 -357 -4 +332 +333 +2 -365 -366 -4 +341 +342 +2 @@ -14220,7 +16291,7 @@ 1 2 -6789 +3374 @@ -14236,7 +16307,7 @@ 1 2 -6789 +3374 @@ -14246,19 +16317,19 @@ attributes -745432 +368399 id -745432 +368399 type_id -1685 +867 target -427033 +219716 @@ -14272,7 +16343,7 @@ 1 2 -745432 +368399 @@ -14288,7 +16359,7 @@ 1 2 -745432 +368399 @@ -14304,67 +16375,67 @@ 1 2 -189 +115 2 3 -194 +85 3 4 -87 +45 4 7 -141 +72 7 -10 -150 +9 +62 -10 -18 -131 +9 +16 +67 -18 -28 -131 +16 +23 +65 -28 -54 -131 +23 +50 +65 -55 -119 -126 +50 +87 +65 -119 -232 -126 +90 +188 +65 -237 -608 -126 +194 +466 +65 -616 -4825 -126 +498 +1735 +65 -5142 -41859 -19 +1785 +41857 +27 @@ -14380,62 +16451,62 @@ 1 2 -316 +165 2 3 -131 +67 3 4 -77 +40 4 6 -141 +72 6 9 -141 +72 9 15 -126 +65 15 -25 -126 +26 +67 -25 -47 -131 +26 +48 +65 -47 -81 -126 +48 +82 +67 -81 -176 -126 +82 +182 +65 -180 -563 -126 +183 +607 +65 -596 -39379 -112 +607 +39377 +52 @@ -14451,17 +16522,17 @@ 1 2 -365083 +188082 2 3 -47483 +24348 3 957 -14465 +7284 @@ -14477,17 +16548,17 @@ 1 2 -394293 +202865 2 16 -32370 +16660 16 20 -370 +190 @@ -14497,15 +16568,15 @@ attribute_location -813489 +403061 id -745432 +368399 loc -72329 +36840 @@ -14519,12 +16590,12 @@ 1 2 -677374 +333737 2 3 -68057 +34662 @@ -14540,12 +16611,12 @@ 1 2 -68125 +34677 4 -26598 -4203 +22087 +2163 @@ -14555,19 +16626,19 @@ type_mention -1248753 +622003 id -1248753 +622003 type_id -35320 +21696 parent -1030328 +541633 @@ -14581,7 +16652,7 @@ 1 2 -1248753 +622003 @@ -14597,7 +16668,7 @@ 1 2 -1248753 +622003 @@ -14613,52 +16684,52 @@ 1 2 -5816 +5029 2 3 -7141 +4912 3 4 -3606 +1876 4 5 -4008 +1650 5 6 -2068 +1080 6 8 -2769 +1622 8 12 -2851 +1671 12 -22 -2719 +24 +1673 -22 -69 -2650 +24 +119 +1633 -69 -80289 -1690 +119 +44145 +547 @@ -14674,52 +16745,47 @@ 1 2 -10023 +6457 2 3 -5791 +4662 3 4 -3445 +1635 4 5 -2998 +1239 5 -6 -2033 +7 +1984 -6 -8 -2535 +7 +11 +1965 -8 -13 -2755 +11 +22 +1628 -13 -29 -2680 +22 +120 +1627 -29 -263 -2649 - - -263 -66416 -407 +120 +38647 +494 @@ -14735,17 +16801,17 @@ 1 2 -876054 +480732 2 3 -138071 +55624 3 -182 -16201 +187 +5276 @@ -14761,12 +16827,12 @@ 1 2 -1011022 +532606 2 22 -19306 +9026 @@ -14776,15 +16842,15 @@ type_mention_location -1248753 +626999 id -1248753 +626999 loc -1167809 +593108 @@ -14798,7 +16864,7 @@ 1 2 -1248753 +626999 @@ -14814,12 +16880,12 @@ 1 2 -1139400 +572155 2 -199 -28408 +187 +20953 @@ -14829,15 +16895,15 @@ type_annotation -50927 +25557 id -50927 +25557 annotation -14 +7 @@ -14851,7 +16917,7 @@ 1 2 -50927 +25557 @@ -14865,19 +16931,19 @@ 12 -1306 -1307 -4 +1305 +1306 +2 -2047 -2048 -4 +2046 +2047 +2 -7103 -7104 -4 +6844 +6845 +2 @@ -14887,15 +16953,15 @@ nullability -1996 +997 nullability -1996 +997 kind -14 +7 @@ -14909,7 +16975,7 @@ 1 2 -1996 +997 @@ -14925,17 +16991,17 @@ 13 14 -4 +2 -127 -128 -4 +120 +121 +2 -270 -271 -4 +265 +266 +2 @@ -14945,19 +17011,19 @@ nullability_parent -6278 +3146 nullability -521 +265 index -102 +52 parent -1982 +990 @@ -14971,22 +17037,22 @@ 1 2 -340 +172 2 3 -116 +60 3 5 -34 +17 5 22 -29 +15 @@ -15002,37 +17068,37 @@ 1 2 -243 +125 2 3 -92 +47 3 4 -53 +30 4 5 -38 +15 5 8 -38 +22 8 -44 -43 +41 +20 -138 -207 -9 +136 +201 +5 @@ -15048,37 +17114,37 @@ 1 2 -19 +10 3 4 -53 +27 5 6 -4 +2 7 8 -4 +2 17 18 -9 +5 39 40 -4 +2 -88 -89 -4 +87 +88 +2 @@ -15094,97 +17160,97 @@ 1 2 -9 +5 2 3 -9 +5 4 5 -4 +2 6 7 -4 +2 8 9 -4 +2 10 11 -4 +2 12 13 -4 +2 14 15 -4 +2 16 17 -4 +2 20 21 -4 +2 22 23 -4 +2 40 41 -4 +2 44 45 -4 +2 -52 -53 -4 +51 +52 +2 -69 -70 -4 +67 +68 +2 -97 -98 -4 +94 +95 +2 -157 -158 -4 +151 +152 +2 -305 -306 -4 +295 +296 +2 -407 -408 -4 +395 +396 +2 @@ -15200,17 +17266,17 @@ 1 2 -594 +295 2 3 -1227 +616 3 4 -160 +77 @@ -15226,37 +17292,37 @@ 1 2 -496 +250 2 3 -720 +360 3 4 -292 +142 4 5 -136 +67 5 8 -141 +67 8 -15 -155 +14 +75 -15 +14 22 -38 +25 @@ -15266,15 +17332,15 @@ type_nullability -4590375 +2271603 id -4523440 +2238788 nullability -954 +601 @@ -15288,12 +17354,12 @@ 1 2 -4462909 +2209099 2 9 -60531 +29689 @@ -15309,62 +17375,57 @@ 1 2 -161 +131 2 3 -141 +81 3 4 -62 +35 4 5 -66 +38 5 7 -80 +48 7 10 -69 +48 10 -14 -73 +13 +46 -14 +13 23 -76 +50 23 -41 -72 +61 +46 -41 -123 -72 +63 +224 +46 -123 -4090 -72 - - -4576 -3672417 -10 +278 +1814893 +32 @@ -15374,11 +17435,11 @@ expr_flowstate -2981562 +1300115 id -2981562 +1300115 state @@ -15396,7 +17457,7 @@ 1 2 -2981562 +1300115 @@ -15410,13 +17471,13 @@ 12 -197309 -197310 +116006 +116007 1 -2193026 -2193027 +1113915 +1113916 1 @@ -15427,23 +17488,23 @@ type_parameters -202686 +102354 id -202686 +102354 index -102 +52 generic_id -103705 +51560 variance -14 +7 @@ -15457,7 +17518,7 @@ 1 2 -202686 +102354 @@ -15473,7 +17534,7 @@ 1 2 -202686 +102354 @@ -15489,7 +17550,7 @@ 1 2 -202686 +102354 @@ -15505,107 +17566,107 @@ 5 6 -4 +2 8 9 -4 +2 12 13 -4 +2 15 16 -4 +2 48 49 -4 +2 170 171 -4 +2 298 299 -4 +2 429 430 -4 +2 560 561 -4 +2 691 692 -4 +2 822 823 -4 +2 954 955 -4 +2 1089 1090 -4 +2 1240 1241 -4 +2 1385 1386 -4 +2 1539 1540 -4 +2 -1757 -1758 -4 +1753 +1754 +2 -2015 -2016 -4 +2007 +2008 +2 -2536 -2537 -4 +2524 +2525 +2 -4744 -4745 -4 +4710 +4711 +2 -21279 -21280 -4 +20558 +20559 +2 @@ -15621,107 +17682,107 @@ 5 6 -4 +2 8 9 -4 +2 12 13 -4 +2 15 16 -4 +2 48 49 -4 +2 170 171 -4 +2 298 299 -4 +2 429 430 -4 +2 560 561 -4 +2 691 692 -4 +2 822 823 -4 +2 954 955 -4 +2 1089 1090 -4 +2 1240 1241 -4 +2 1385 1386 -4 +2 1539 1540 -4 +2 -1757 -1758 -4 +1753 +1754 +2 -2015 -2016 -4 +2007 +2008 +2 -2536 -2537 -4 +2524 +2525 +2 -4748 -4749 -4 +4712 +4713 +2 -21292 -21293 -4 +20568 +20569 +2 @@ -15737,17 +17798,17 @@ 1 2 -19 +10 2 3 -4 +2 3 4 -77 +40 @@ -15763,22 +17824,22 @@ 1 2 -80579 +39748 2 3 -10773 +5484 3 -11 -8348 +10 +3935 -11 +10 22 -4003 +2391 @@ -15794,22 +17855,22 @@ 1 2 -80579 +39748 2 3 -10773 +5484 3 -11 -8348 +10 +3935 -11 +10 22 -4003 +2391 @@ -15825,12 +17886,12 @@ 1 2 -103554 +51482 2 3 -150 +77 @@ -15846,17 +17907,17 @@ 68 69 -4 +2 310 311 -4 +2 -41219 -41220 -4 +40440 +40441 +2 @@ -15872,17 +17933,17 @@ 16 17 -4 +2 17 18 -4 +2 21 22 -4 +2 @@ -15898,17 +17959,17 @@ 65 66 -4 +2 72 73 -4 +2 -21186 -21187 -4 +20462 +20463 +2 @@ -15918,19 +17979,19 @@ type_arguments -643772 +315219 id -273252 +136875 index -102 +52 constructed_id -412879 +201248 @@ -15944,17 +18005,17 @@ 1 2 -234662 +119004 2 3 -37114 +17166 3 21 -1475 +704 @@ -15970,27 +18031,27 @@ 1 2 -173930 +88393 2 3 -56470 +27419 3 5 -20568 +10305 5 -23 -20651 +25 +10278 -23 -2800 -1631 +25 +2394 +478 @@ -16006,97 +18067,97 @@ 2 3 -14 +7 3 4 -4 +2 55 56 -4 +2 167 168 -4 +2 283 284 -4 +2 402 403 -4 +2 521 522 -4 +2 640 641 -4 +2 759 760 -4 +2 883 884 -4 +2 1002 1003 -4 +2 1232 1233 -4 +2 1327 1328 -4 +2 -1515 -1516 -4 +1510 +1511 +2 -1729 -1730 -4 +1717 +1718 +2 -2010 -2011 -4 +1979 +1980 +2 -4190 -4191 -4 +3839 +3840 +2 -14311 -14312 -4 +13565 +13566 +2 -33697 -33698 -4 +32507 +32508 +2 @@ -16112,97 +18173,97 @@ 2 3 -9 +5 3 4 -9 +5 96 97 -4 +2 227 228 -4 +2 365 366 -4 +2 503 504 -4 +2 641 642 -4 +2 779 780 -4 +2 917 918 -4 +2 1061 1062 -4 +2 1201 1202 -4 +2 1456 1457 -4 +2 -1643 -1644 -4 +1641 +1642 +2 -1866 -1867 -4 +1859 +1860 +2 -2254 -2255 -4 +2240 +2241 +2 -3022 -3023 -4 +2987 +2988 +2 -5701 -5702 -4 +5285 +5286 +2 -25663 -25664 -4 +24196 +24197 +2 -84769 -84770 -4 +80280 +80281 +2 @@ -16218,17 +18279,17 @@ 1 2 -290046 +141661 2 3 -96229 +46887 3 22 -26603 +12699 @@ -16244,17 +18305,17 @@ 1 2 -287884 +140593 2 3 -97227 +47406 3 22 -27767 +13248 @@ -16264,15 +18325,15 @@ constructed_generic -412879 +201248 constructed -412879 +201248 generic -8577 +4256 @@ -16286,7 +18347,7 @@ 1 2 -412879 +201248 @@ -16302,47 +18363,47 @@ 1 2 -3443 +1737 2 3 -1154 +551 3 4 -618 +293 4 6 -652 +330 6 11 -725 +350 11 -26 -647 +25 +328 -26 -63 -657 +25 +61 +320 -63 -2866 -647 +61 +2054 +320 -2964 -11327 -29 +2323 +10856 +22 @@ -16352,15 +18413,15 @@ type_parameter_constraints -591856 +273733 id -591856 +273733 param_id -202599 +102321 @@ -16374,7 +18435,7 @@ 1 2 -591856 +273733 @@ -16390,22 +18451,17 @@ 1 2 -167248 +86049 2 3 -19984 +9393 3 -307 -15201 - - -310 -2107 -165 +1740 +6878 @@ -16451,11 +18507,11 @@ general_type_parameter_constraints -106710 +40912 id -60470 +23697 kind @@ -16473,12 +18529,12 @@ 1 2 -14230 +6482 2 3 -46240 +17215 @@ -16497,23 +18553,23 @@ 1 -281 -282 +172 +173 1 -5846 -5847 +2708 +2709 1 -46183 -46184 +17170 +17171 1 -54396 -54397 +20858 +20859 1 @@ -16524,15 +18580,15 @@ specific_type_parameter_constraints -46374 +20140 id -45669 +19736 base_id -1286 +787 @@ -16546,12 +18602,12 @@ 1 2 -45010 +19370 2 5 -659 +366 @@ -16572,58 +18628,48 @@ 2 3 -257 +181 3 4 -73 +57 4 5 -91 +87 5 -6 -58 - - -6 7 -138 +70 7 10 -108 +53 10 15 -99 +63 15 -21 -111 - - -21 -37 -97 - - -37 -106 -97 - - -108 -4906 +26 60 + +26 +55 +61 + + +56 +3216 +58 + @@ -16632,19 +18678,19 @@ specific_type_parameter_nullability -31513 +13207 id -31366 +13161 base_id -911 +506 nullability -17 +11 @@ -16658,12 +18704,12 @@ 1 2 -31219 +13115 2 3 -147 +46 @@ -16679,7 +18725,7 @@ 1 2 -31366 +13161 @@ -16695,67 +18741,57 @@ 1 2 -97 +99 2 3 -150 +107 3 4 -48 +37 4 5 -41 +31 5 6 -52 +16 6 7 -102 +41 7 -9 -72 +10 +32 -9 -12 -46 +10 +13 +39 -12 -16 -69 +13 +26 +38 -16 -22 -71 +26 +82 +40 -22 -39 -71 - - -39 -186 -69 - - -190 -4327 -23 +84 +2385 +26 @@ -16771,12 +18807,12 @@ 1 2 -889 +497 2 3 -22 +9 @@ -16797,37 +18833,17 @@ 4 5 -1 +2 6 7 -3 +1 8 9 -1 - - -10 -11 -1 - - -12 -13 -1 - - -16 -17 -1 - - -18 -19 -1 +2 24 @@ -16835,28 +18851,18 @@ 1 -64 -65 +41 +42 1 -72 -73 +132 +133 1 -117 -118 -1 - - -386 -387 -1 - - -30613 -30614 +12930 +12931 1 @@ -16873,12 +18879,12 @@ 1 2 -6 +2 2 3 -3 +4 3 @@ -16888,26 +18894,21 @@ 5 6 -2 +1 + + +6 +7 +1 9 10 -2 - - -12 -13 1 -43 -44 -1 - - -835 -836 +482 +483 1 @@ -16918,15 +18919,15 @@ function_pointer_calling_conventions -11 +9 id -11 +9 kind -1 +2 @@ -16940,7 +18941,7 @@ 1 2 -11 +9 @@ -16954,8 +18955,13 @@ 12 -9 -10 +1 +2 +1 + + +8 +9 1 @@ -17046,15 +19052,15 @@ modifiers -82 +42 id -82 +42 name -82 +42 @@ -17068,7 +19074,7 @@ 1 2 -82 +42 @@ -17084,7 +19090,7 @@ 1 2 -82 +42 @@ -17094,15 +19100,15 @@ has_modifiers -5495911 +2748133 id -3690851 +1841097 mod_id -82 +40 @@ -17116,17 +19122,17 @@ 1 2 -2021272 +1002460 2 3 -1535937 +771185 3 5 -133640 +67451 @@ -17140,89 +19146,84 @@ 12 -1 -2 -4 - - -15 -16 -4 +5 +6 +2 28 29 -4 +2 -151 -152 -4 +149 +150 +2 360 361 -4 +2 -6163 -6164 -4 +5658 +5659 +2 -16387 -16388 -4 +16373 +16374 +2 -23881 -23882 -4 +22977 +22978 +2 -30035 -30036 -4 +29954 +29955 +2 -30699 -30700 -4 +30538 +30539 +2 -38027 -38028 -4 +37974 +37975 +2 -62139 -62140 -4 +60421 +60422 +2 -63917 -63918 -4 +63249 +63250 +2 -68706 -68707 -4 +68508 +68509 +2 -83361 -83362 -4 +78672 +78673 +2 -95562 -95563 -4 +89979 +89980 +2 -608943 -608944 -4 +591411 +591412 +2 @@ -17232,26 +19233,26 @@ compiler_generated -135842 +64039 id -135842 +64039 exprorstmt_name -3765 +1469 parent_id -3765 +1469 name -375 +118 @@ -17265,7 +19266,7 @@ 1 2 -3765 +1469 @@ -17281,47 +19282,47 @@ 2 3 -111 +43 3 4 -56 +9 4 5 -51 +12 5 -6 -34 +7 +10 -6 -8 -32 +7 +9 +9 -8 -12 -28 +10 +15 +9 -12 -23 -31 +16 +26 +7 -25 -214 -28 +26 +52 +10 -239 -240 -1 +54 +131 +5 @@ -17331,19 +19332,19 @@ nested_types -111932 +57075 id -111932 +57075 declaring_type_id -40596 +20621 unbound_id -81115 +41748 @@ -17357,7 +19358,7 @@ 1 2 -111932 +57075 @@ -17373,7 +19374,7 @@ 1 2 -111932 +57075 @@ -17389,32 +19390,32 @@ 1 2 -23486 +11922 2 3 -6336 +3253 3 4 -3229 +1566 4 7 -3355 +1732 7 12 -3092 +1581 12 262 -1095 +564 @@ -17430,32 +19431,32 @@ 1 2 -23520 +11940 2 3 -6419 +3296 3 4 -3146 +1524 4 7 -3385 +1742 7 12 -3078 +1579 12 206 -1047 +538 @@ -17471,12 +19472,12 @@ 1 2 -78100 +40237 2 415 -3014 +1511 @@ -17492,12 +19493,12 @@ 1 2 -78841 +40613 2 415 -2274 +1135 @@ -17507,27 +19508,27 @@ properties -423531 +212542 id -423531 +212542 name -84359 +43400 declaring_type_id -116374 +58256 type_id -52125 +26015 unbound_id -333843 +171648 @@ -17541,7 +19542,7 @@ 1 2 -423531 +212542 @@ -17557,7 +19558,7 @@ 1 2 -423531 +212542 @@ -17573,7 +19574,7 @@ 1 2 -423531 +212542 @@ -17589,7 +19590,7 @@ 1 2 -423531 +212542 @@ -17605,32 +19606,32 @@ 1 2 -50752 +26111 2 3 -13993 +7204 3 4 -5752 +2970 4 7 -6648 +3414 7 -49 -6336 +50 +3276 -49 -2611 -876 +50 +2493 +423 @@ -17646,32 +19647,32 @@ 1 2 -50752 +26111 2 3 -14061 +7239 3 4 -5737 +2963 4 7 -6682 +3431 7 -51 -6331 +52 +3256 -51 -2578 -793 +52 +2224 +398 @@ -17687,17 +19688,17 @@ 1 2 -72835 +37474 2 3 -6930 +3569 3 -524 -4593 +522 +2356 @@ -17713,32 +19714,32 @@ 1 2 -51180 +26331 2 3 -14256 +7340 3 4 -5737 +2963 4 7 -6443 +3304 7 -68 -6326 +70 +3256 -68 +70 2018 -414 +205 @@ -17754,42 +19755,42 @@ 1 2 -39384 +19786 2 3 -29866 +14574 3 4 -10900 +5590 4 5 -7841 +4013 5 6 -7130 +3629 6 8 -9327 +4670 8 -16 -9565 +15 +4396 -16 +15 250 -2357 +1594 @@ -17805,42 +19806,42 @@ 1 2 -43894 +22107 2 3 -25434 +12293 3 4 -10895 +5587 4 5 -7861 +4023 5 6 -7145 +3637 6 8 -9283 +4647 8 -14 -8742 +15 +4605 -14 +15 250 -3117 +1353 @@ -17856,32 +19857,32 @@ 1 2 -45447 +22884 2 3 -32613 +15963 3 4 -13837 +6963 4 5 -7544 +3873 5 7 -9380 +4828 7 48 -7549 +3742 @@ -17897,42 +19898,42 @@ 1 2 -39384 +19786 2 3 -29866 +14574 3 4 -10900 +5590 4 5 -7841 +4013 5 6 -7130 +3629 6 8 -9327 +4670 8 -16 -9565 +15 +4396 -16 +15 250 -2357 +1594 @@ -17948,27 +19949,27 @@ 1 2 -31415 +15635 2 3 -10778 +5319 3 5 -4631 +2353 5 -21 -3945 +19 +1955 -21 -12516 -1354 +19 +11856 +752 @@ -17984,17 +19985,17 @@ 1 2 -44074 +21932 2 3 -4398 +2213 3 3289 -3652 +1870 @@ -18010,27 +20011,27 @@ 1 2 -32599 +16244 2 3 -10481 +5169 3 5 -4422 +2243 5 -33 -3911 +30 +1952 -33 -6176 -711 +30 +5894 +406 @@ -18046,27 +20047,27 @@ 1 2 -31556 +15707 2 3 -10910 +5392 3 5 -4666 +2356 5 -22 -3911 +21 +1975 -22 -10632 -1081 +21 +10599 +584 @@ -18082,12 +20083,12 @@ 1 2 -328670 +169043 2 -705 -5172 +585 +2604 @@ -18103,7 +20104,7 @@ 1 2 -333843 +171648 @@ -18119,12 +20120,12 @@ 1 2 -328670 +169043 2 -705 -5172 +585 +2604 @@ -18140,12 +20141,12 @@ 1 2 -332635 +171048 2 -439 -1207 +438 +599 @@ -18155,15 +20156,15 @@ property_location -534450 +263937 id -423531 +212542 loc -52895 +24308 @@ -18177,17 +20178,17 @@ 1 2 -338105 +171527 2 3 -64102 +32779 3 119 -21323 +8234 @@ -18203,12 +20204,12 @@ 1 2 -49412 +22594 2 7080 -3482 +1714 @@ -18218,27 +20219,27 @@ indexers -17042 +7590 id -17042 +7590 name -19 +10 declaring_type_id -13550 +6071 type_id -3969 +1817 unbound_id -4437 +2283 @@ -18252,7 +20253,7 @@ 1 2 -17042 +7590 @@ -18268,7 +20269,7 @@ 1 2 -17042 +7590 @@ -18284,7 +20285,7 @@ 1 2 -17042 +7590 @@ -18300,7 +20301,7 @@ 1 2 -17042 +7590 @@ -18316,22 +20317,22 @@ 2 3 -4 +2 3 4 -4 +2 6 7 -4 +2 -3488 -3489 -4 +3017 +3018 +2 @@ -18347,22 +20348,22 @@ 2 3 -4 +2 3 4 -4 +2 4 5 -4 +2 -2775 -2776 -4 +2415 +2416 +2 @@ -18378,17 +20379,17 @@ 1 2 -9 +5 4 5 -4 +2 -810 -811 -4 +720 +721 +2 @@ -18404,22 +20405,22 @@ 2 3 -4 +2 3 4 -4 +2 6 7 -4 +2 900 901 -4 +2 @@ -18435,17 +20436,17 @@ 1 2 -10505 +4770 2 3 -2747 +1160 3 7 -297 +140 @@ -18461,12 +20462,12 @@ 1 2 -13540 +6066 2 3 -9 +5 @@ -18482,12 +20483,12 @@ 1 2 -11046 +5046 2 3 -2503 +1025 @@ -18503,17 +20504,17 @@ 1 2 -10505 +4770 2 3 -2747 +1160 3 7 -297 +140 @@ -18529,32 +20530,27 @@ 1 2 -876 +461 2 3 -871 +423 3 4 -1626 +674 4 6 -267 +120 6 -18 -301 - - -18 -1020 -24 +886 +137 @@ -18570,12 +20566,12 @@ 1 2 -3964 +1814 2 3 -4 +2 @@ -18591,27 +20587,27 @@ 1 2 -1032 +541 2 3 -779 +376 3 4 -1660 +691 4 -6 -238 +7 +165 -6 -978 -258 +7 +845 +42 @@ -18627,27 +20623,27 @@ 1 2 -876 +461 2 3 -871 +423 3 4 -1651 +686 4 6 -267 +120 6 198 -301 +125 @@ -18663,12 +20659,12 @@ 1 2 -4101 +2118 2 -452 -336 +384 +165 @@ -18684,7 +20680,7 @@ 1 2 -4437 +2283 @@ -18700,12 +20696,12 @@ 1 2 -4101 +2118 2 -452 -336 +384 +165 @@ -18721,12 +20717,12 @@ 1 2 -4247 +2190 2 -452 -189 +384 +92 @@ -18736,15 +20732,15 @@ indexer_location -23715 +12780 id -12621 +6439 loc -220 +183 @@ -18758,27 +20754,27 @@ 1 2 -4492 +2232 2 3 -6616 +3081 3 4 -284 +283 4 5 -1115 +774 5 -13 -114 +11 +69 @@ -18794,17 +20790,17 @@ 1 2 -75 +49 2 3 -22 +20 3 4 -18 +19 4 @@ -18814,32 +20810,32 @@ 5 8 -18 +14 8 13 -16 +14 13 -21 -18 +20 +14 -23 -45 -19 +20 +35 +14 -47 -2230 -17 +36 +112 +14 -3540 -5425 -3 +124 +2196 +11 @@ -18849,27 +20845,27 @@ accessors -567868 +284483 id -567868 +284483 kind -9 +5 name -121244 +62337 declaring_member_id -440574 +220132 unbound_id -440423 +226384 @@ -18883,7 +20879,7 @@ 1 2 -567868 +284483 @@ -18899,7 +20895,7 @@ 1 2 -567868 +284483 @@ -18915,7 +20911,7 @@ 1 2 -567868 +284483 @@ -18931,7 +20927,7 @@ 1 2 -567868 +284483 @@ -18945,14 +20941,14 @@ 12 -26183 -26184 -4 +25718 +25719 +2 -90407 -90408 -4 +87765 +87766 +2 @@ -18966,14 +20962,14 @@ 12 -6520 -6521 -4 +6501 +6502 +2 -18373 -18374 -4 +18366 +18367 +2 @@ -18987,14 +20983,14 @@ 12 -26182 -26183 -4 +25717 +25718 +2 -90406 -90407 -4 +87764 +87765 +2 @@ -19008,14 +21004,14 @@ 12 -21018 -21019 -4 +20971 +20972 +2 -69406 -69407 -4 +69336 +69337 +2 @@ -19031,27 +21027,27 @@ 1 2 -75192 +38650 2 3 -19950 +10267 3 4 -7929 +4103 4 8 -10126 +5186 8 -2558 -8046 +2204 +4128 @@ -19067,7 +21063,7 @@ 1 2 -121244 +62337 @@ -19083,27 +21079,27 @@ 1 2 -75202 +38655 2 3 -19940 +10262 3 4 -7929 +4103 4 8 -10126 +5186 8 -2558 -8046 +2204 +4128 @@ -19119,27 +21115,27 @@ 1 2 -75840 +38981 2 3 -20617 +10611 3 4 -7763 +4020 4 8 -9653 +4933 8 1202 -7369 +3790 @@ -19155,17 +21151,17 @@ 1 2 -313289 +155787 2 3 -127279 +64342 4 5 -4 +2 @@ -19181,12 +21177,12 @@ 1 2 -313289 +155787 2 3 -127284 +64345 @@ -19202,12 +21198,12 @@ 1 2 -313289 +155787 2 3 -127284 +64345 @@ -19223,17 +21219,17 @@ 1 2 -313289 +155787 2 3 -127279 +64342 4 5 -4 +2 @@ -19249,12 +21245,12 @@ 1 2 -433759 +223033 2 -705 -6663 +585 +3351 @@ -19270,7 +21266,7 @@ 1 2 -440423 +226384 @@ -19286,7 +21282,7 @@ 1 2 -440423 +226384 @@ -19302,12 +21298,12 @@ 1 2 -433759 +223033 2 -705 -6663 +585 +3351 @@ -19328,15 +21324,15 @@ accessor_location -747775 +367482 id -567868 +284483 loc -93214 +43067 @@ -19350,17 +21346,17 @@ 1 2 -432707 +219889 2 3 -98396 +50297 3 119 -36763 +14296 @@ -19376,12 +21372,12 @@ 1 2 -89610 +41305 2 -8294 -3604 +7862 +1762 @@ -19391,27 +21387,27 @@ events -15230 +7838 id -15230 +7838 name -12990 +6685 declaring_type_id -1227 +631 type_id -6365 +3276 unbound_id -15220 +7833 @@ -19425,7 +21421,7 @@ 1 2 -15230 +7838 @@ -19441,7 +21437,7 @@ 1 2 -15230 +7838 @@ -19457,7 +21453,7 @@ 1 2 -15230 +7838 @@ -19473,7 +21469,7 @@ 1 2 -15230 +7838 @@ -19489,17 +21485,17 @@ 1 2 -12001 +6176 2 12 -978 +503 14 17 -9 +5 @@ -19515,17 +21511,17 @@ 1 2 -12001 +6176 2 10 -978 +503 14 17 -9 +5 @@ -19541,12 +21537,12 @@ 1 2 -12848 +6613 2 10 -141 +72 @@ -19562,17 +21558,17 @@ 1 2 -12001 +6176 2 12 -978 +503 14 17 -9 +5 @@ -19588,32 +21584,32 @@ 1 2 -618 +318 2 3 -228 +117 3 4 -97 +50 4 8 -107 +55 8 23 -102 +52 58 465 -73 +37 @@ -19629,32 +21625,32 @@ 1 2 -618 +318 2 3 -238 +122 3 4 -92 +47 4 8 -102 +52 8 23 -102 +52 58 465 -73 +37 @@ -19670,27 +21666,27 @@ 1 2 -769 +396 2 3 -199 +102 3 5 -87 +45 5 11 -92 +47 12 181 -77 +40 @@ -19706,32 +21702,32 @@ 1 2 -618 +318 2 3 -228 +117 3 4 -97 +50 4 8 -107 +55 8 23 -102 +52 58 465 -73 +37 @@ -19747,22 +21743,22 @@ 1 2 -4412 +2271 2 3 -1164 +599 3 6 -516 +265 6 318 -272 +140 @@ -19778,22 +21774,22 @@ 1 2 -4802 +2471 2 3 -915 +471 3 8 -501 +258 8 242 -146 +75 @@ -19809,17 +21805,17 @@ 1 2 -5752 +2960 2 4 -521 +268 4 27 -92 +47 @@ -19835,22 +21831,22 @@ 1 2 -4412 +2271 2 3 -1164 +599 3 6 -516 +265 6 318 -272 +140 @@ -19866,12 +21862,12 @@ 1 2 -15211 +7828 2 3 -9 +5 @@ -19887,7 +21883,7 @@ 1 2 -15220 +7833 @@ -19903,12 +21899,12 @@ 1 2 -15211 +7828 2 3 -9 +5 @@ -19924,12 +21920,12 @@ 1 2 -15211 +7828 2 3 -9 +5 @@ -19939,15 +21935,15 @@ event_location -15868 +8167 id -15230 +7838 loc -326 +167 @@ -19961,12 +21957,12 @@ 1 2 -14592 +7510 2 3 -638 +328 @@ -19982,57 +21978,57 @@ 1 2 -48 +25 2 3 -48 +25 3 4 -43 +22 4 5 -24 +12 5 6 -14 +7 6 8 -24 +12 8 9 -19 +10 10 11 -19 +10 12 16 -29 +15 16 31 -29 +15 64 2199 -24 +12 @@ -20042,27 +22038,27 @@ event_accessors -30461 +15677 id -30461 +15677 kind -9 +5 name -26691 +13737 declaring_event_id -15230 +7838 unbound_id -30441 +15667 @@ -20076,7 +22072,7 @@ 1 2 -30461 +15677 @@ -20092,7 +22088,7 @@ 1 2 -30461 +15677 @@ -20108,7 +22104,7 @@ 1 2 -30461 +15677 @@ -20124,7 +22120,7 @@ 1 2 -30461 +15677 @@ -20140,7 +22136,7 @@ 3127 3128 -9 +5 @@ -20156,7 +22152,7 @@ 2740 2741 -9 +5 @@ -20172,7 +22168,7 @@ 3127 3128 -9 +5 @@ -20188,7 +22184,7 @@ 3125 3126 -9 +5 @@ -20204,12 +22200,12 @@ 1 2 -24703 +12714 2 16 -1987 +1022 @@ -20225,7 +22221,7 @@ 1 2 -26691 +13737 @@ -20241,12 +22237,12 @@ 1 2 -24703 +12714 2 16 -1987 +1022 @@ -20262,12 +22258,12 @@ 1 2 -24703 +12714 2 16 -1987 +1022 @@ -20283,7 +22279,7 @@ 2 3 -15230 +7838 @@ -20299,7 +22295,7 @@ 2 3 -15230 +7838 @@ -20315,7 +22311,7 @@ 2 3 -15230 +7838 @@ -20331,7 +22327,7 @@ 2 3 -15230 +7838 @@ -20347,12 +22343,12 @@ 1 2 -30422 +15657 2 3 -19 +10 @@ -20368,7 +22364,7 @@ 1 2 -30441 +15667 @@ -20384,7 +22380,7 @@ 1 2 -30441 +15667 @@ -20400,12 +22396,12 @@ 1 2 -30422 +15657 2 3 -19 +10 @@ -20415,15 +22411,15 @@ event_accessor_location -31737 +16334 id -30461 +15677 loc -326 +167 @@ -20437,12 +22433,12 @@ 1 2 -29184 +15020 2 3 -1276 +656 @@ -20458,57 +22454,57 @@ 2 3 -48 +25 4 5 -48 +25 6 7 -43 +22 8 9 -24 +12 10 11 -14 +7 12 15 -24 +12 16 17 -19 +10 20 21 -19 +10 24 31 -29 +15 32 61 -29 +15 128 4397 -24 +12 @@ -20518,31 +22514,31 @@ operators -12410 +6201 id -12410 +6201 name -126 +65 symbol -116 +60 declaring_type_id -3024 +1448 type_id -1621 +809 unbound_id -11655 +5903 @@ -20556,7 +22552,7 @@ 1 2 -12410 +6201 @@ -20572,7 +22568,7 @@ 1 2 -12410 +6201 @@ -20588,7 +22584,7 @@ 1 2 -12410 +6201 @@ -20604,7 +22600,7 @@ 1 2 -12410 +6201 @@ -20620,7 +22616,7 @@ 1 2 -12410 +6201 @@ -20636,72 +22632,67 @@ 1 2 -4 +2 2 3 -19 +10 3 -5 -9 +4 +5 5 6 -4 +2 8 9 -9 +7 -9 -11 -9 +10 +17 +5 -17 -27 -9 - - -45 +26 46 -4 +5 54 55 -9 +5 57 58 -9 +5 -66 -74 -9 +65 +73 +5 -85 -437 -9 +80 +436 +5 -459 -532 -9 +454 +500 +5 -532 -533 -4 +506 +507 +2 @@ -20717,7 +22708,7 @@ 1 2 -126 +65 @@ -20733,74 +22724,374 @@ 1 2 -4 +2 2 3 -19 +10 3 -5 -9 +4 +5 5 6 -4 +2 8 9 -9 +7 -9 -11 -9 +10 +15 +5 -15 -27 -9 +26 +32 +5 + + +36 +50 +5 + + +50 +52 +5 + + +52 +53 +5 + + +63 +120 +5 + + +201 +444 +5 + + +451 +452 +2 + + + + + + +name +type_id + + +12 + + +1 +2 +7 + + +2 +3 +20 + + +3 +4 +5 + + +5 +6 +2 + + +8 +9 +7 + + +10 +15 +5 + + +26 +32 +5 + + +37 +52 +5 + + +63 +155 +5 + + +181 +182 +2 + + + + + + +name +unbound_id + + +12 + + +1 +2 +2 + + +2 +3 +10 + + +3 +4 +5 + + +5 +6 +2 + + +8 +9 +7 + + +10 +17 +5 + + +26 +46 +5 + + +53 +54 +5 + + +56 +57 +5 + + +65 +73 +5 + + +80 +415 +5 + + +416 +472 +5 + + +478 +479 +2 + + + + + + +symbol +id + + +12 + + +1 +2 +2 + + +2 +3 +10 + + +3 +4 +5 + + +8 +9 +7 + + +10 +17 +5 + + +45 +46 +2 + + +54 +55 +5 + + +57 +58 +5 + + +72 +86 +5 + + +91 +436 +5 + + +454 +500 +5 + + +506 +507 +2 + + + + + + +symbol +name + + +12 + + +1 +2 +55 + + +2 +3 +5 + + + + + + +symbol +declaring_type_id + + +12 + + +1 +2 +2 + + +2 +3 +10 + + +3 +4 +5 + + +8 +9 +7 + + +10 +15 +5 31 -38 -9 +37 +5 49 51 -9 +5 + + +51 +52 +2 52 53 -14 +5 -68 -121 -9 +63 +120 +5 -206 -476 -9 +201 +444 +5 -477 -478 -4 +451 +452 +2 -name +symbol type_id @@ -20809,59 +23100,49 @@ 1 2 -14 +7 2 3 -38 +20 3 -5 -9 - - -5 -6 -4 +4 +5 8 9 -9 +7 -9 -11 -9 - - -15 -27 -9 +10 +15 +5 31 -39 -9 +38 +5 -52 -69 -9 +51 +64 +5 -155 -186 -9 +154 +182 +5 -name +symbol unbound_id @@ -20870,362 +23151,62 @@ 1 2 -4 +2 2 3 -19 +10 3 -5 -9 - - -5 -6 -4 +4 +5 8 9 -9 +7 -9 -11 -9 - - -17 -27 -9 +10 +17 +5 45 46 -4 +2 53 54 -9 +5 56 57 -9 +5 -66 -74 -9 +72 +86 +5 -85 +91 415 -9 +5 416 -489 -9 +472 +5 -489 -490 -4 - - - - - - -symbol -id - - -12 - - -1 -2 -4 - - -2 -3 -19 - - -3 -5 -9 - - -8 -9 -9 - - -9 -11 -9 - - -17 -46 -9 - - -54 -55 -9 - - -57 -58 -9 - - -73 -91 -9 - - -92 -437 -9 - - -459 -532 -9 - - -532 -533 -4 - - - - - - -symbol -name - - -12 - - -1 -2 -107 - - -2 -3 -9 - - - - - - -symbol -declaring_type_id - - -12 - - -1 -2 -4 - - -2 -3 -19 - - -3 -5 -9 - - -8 -9 -9 - - -9 -11 -9 - - -15 -32 -9 - - -37 -50 -9 - - -50 -51 -4 - - -52 -53 -14 - - -68 -121 -9 - - -206 -476 -9 - - -477 -478 -4 - - - - - - -symbol -type_id - - -12 - - -1 -2 -14 - - -2 -3 -38 - - -3 -5 -9 - - -8 -9 -9 - - -9 -11 -9 - - -15 -32 -9 - - -38 -53 -9 - - -68 -156 -9 - - -185 -186 -4 - - - - - - -symbol -unbound_id - - -12 - - -1 -2 -4 - - -2 -3 -19 - - -3 -5 -9 - - -8 -9 -9 - - -9 -11 -9 - - -17 -46 -9 - - -53 -54 -9 - - -56 -57 -9 - - -73 -91 -9 - - -92 -415 -9 - - -416 -489 -9 - - -489 -490 -4 +478 +479 +2 @@ -21241,37 +23222,42 @@ 1 2 -472 +200 2 3 -1568 +742 3 4 -87 +45 4 +5 +115 + + +5 6 -267 +22 6 7 -287 +147 7 -16 -228 +15 +112 -16 +15 73 -112 +62 @@ -21287,32 +23273,32 @@ 1 2 -628 +280 2 3 -1539 +726 3 4 -243 +125 4 5 -272 +142 5 10 -243 +125 10 24 -97 +47 @@ -21328,32 +23314,32 @@ 1 2 -628 +280 2 3 -1543 +729 3 4 -238 +122 4 5 -272 +142 5 9 -228 +115 9 22 -112 +57 @@ -21369,27 +23355,27 @@ 1 2 -2021 +945 2 3 -418 +203 3 4 -292 +150 4 -6 -243 +5 +112 -8 +5 39 -48 +37 @@ -21405,37 +23391,42 @@ 1 2 -472 +200 2 3 -1568 +742 3 4 -87 +45 4 +5 +115 + + +5 6 -267 +22 6 7 -287 +147 7 -16 -228 +15 +112 -16 +15 73 -112 +62 @@ -21451,32 +23442,32 @@ 1 2 -793 +383 2 3 -370 +190 3 5 -121 +62 5 8 -126 +65 8 18 -126 +65 -19 -1227 -82 +18 +1167 +42 @@ -21492,27 +23483,27 @@ 1 2 -1207 +596 2 3 -150 +77 3 5 -116 +60 5 13 -131 +70 13 18 -14 +5 @@ -21528,27 +23519,27 @@ 1 2 -1207 +596 2 3 -160 +82 3 5 -126 +65 5 14 -121 +62 15 16 -4 +2 @@ -21564,22 +23555,22 @@ 1 2 -1266 +626 2 3 -121 +62 3 6 -126 +65 6 -501 -107 +463 +55 @@ -21595,32 +23586,32 @@ 1 2 -793 +383 2 3 -370 +190 3 5 -121 +62 5 8 -126 +65 8 18 -126 +65 -19 -1137 -82 +18 +1107 +42 @@ -21636,12 +23627,12 @@ 1 2 -11509 +5828 2 -26 -146 +21 +75 @@ -21657,7 +23648,7 @@ 1 2 -11655 +5903 @@ -21673,7 +23664,7 @@ 1 2 -11655 +5903 @@ -21689,12 +23680,12 @@ 1 2 -11509 +5828 2 -26 -146 +21 +75 @@ -21710,12 +23701,12 @@ 1 2 -11597 +5873 2 -22 -58 +21 +30 @@ -21725,15 +23716,15 @@ operator_location -22843 +11639 id -5785 +1989 loc -3241 +1713 @@ -21747,32 +23738,47 @@ 1 2 -861 +438 2 3 -3233 +221 3 +6 +182 + + +6 +7 +41 + + +7 +8 +257 + + +8 9 -396 +122 9 -11 -461 +10 +495 -11 +10 12 -597 +119 12 -14 -234 +13 +108 @@ -21788,17 +23794,22 @@ 1 2 -2841 +1403 2 -9 -243 +3 +115 -9 -2695 -157 +3 +15 +131 + + +21 +793 +63 @@ -21808,15 +23819,15 @@ constant_value -185352 +95257 id -185240 +95199 value -47854 +24531 @@ -21830,12 +23841,12 @@ 1 2 -185128 +95141 2 3 -112 +57 @@ -21851,27 +23862,27 @@ 1 2 -32891 +16848 2 3 -7218 +3705 3 4 -3886 +1995 4 -61 -3589 +60 +1842 -61 +60 2421 -267 +140 @@ -21881,27 +23892,27 @@ methods -1116872 +549172 id -1116872 +549172 name -133791 +68273 declaring_type_id -202248 +101140 type_id -112877 +54054 unbound_id -696794 +357745 @@ -21915,7 +23926,7 @@ 1 2 -1116872 +549172 @@ -21931,7 +23942,7 @@ 1 2 -1116872 +549172 @@ -21947,7 +23958,7 @@ 1 2 -1116872 +549172 @@ -21963,7 +23974,7 @@ 1 2 -1116872 +549172 @@ -21979,32 +23990,32 @@ 1 2 -69318 +35183 2 3 -23632 +12138 3 4 -10842 +5557 4 6 -10423 +5404 6 12 -10569 +5429 12 -5621 -9005 +5061 +4559 @@ -22020,32 +24031,32 @@ 1 2 -79688 +40500 2 3 -19355 +9934 3 4 -11324 +5820 4 7 -11046 +5698 7 -33 -10106 +32 +5131 -33 +32 4959 -2269 +1188 @@ -22061,22 +24072,22 @@ 1 2 -113057 +57652 2 3 -10593 +5432 3 -209 -10038 +126 +5121 -222 -2703 -102 +137 +2143 +67 @@ -22092,32 +24103,32 @@ 1 2 -71057 +36040 2 3 -24499 +12589 3 4 -10915 +5607 4 6 -10720 +5512 6 -13 -10720 +12 +5149 -13 +12 4958 -5878 +3374 @@ -22133,42 +24144,42 @@ 1 2 -59918 +30224 2 3 -43002 +21964 3 4 -31293 +15156 4 5 -14251 +7172 5 6 -14787 +7264 6 10 -16097 +8104 10 23 -15654 +7831 23 -1309 -7242 +1055 +3421 @@ -22184,37 +24195,37 @@ 1 2 -64984 +32832 2 3 -44688 +22819 3 4 -34391 +16580 4 5 -18191 +9122 5 8 -18157 +8951 8 18 -15249 +7600 18 457 -6585 +3233 @@ -22230,32 +24241,32 @@ 1 2 -98011 +49695 2 3 -48906 +23712 3 4 -22945 +11686 4 5 -11621 +5946 5 -10 -15206 +11 +7863 -10 -738 -5557 +11 +595 +2236 @@ -22271,42 +24282,42 @@ 1 2 -60025 +30277 2 3 -43080 +21994 3 4 -31293 +15158 4 5 -14285 +7184 5 6 -14806 +7267 6 10 -16014 +8069 10 23 -16112 +8069 23 698 -6628 +3118 @@ -22322,27 +24333,27 @@ 1 2 -75436 +35802 2 3 -14480 +6943 3 4 -8309 +4078 4 -10 -8825 +9 +4086 -10 -62181 -5825 +9 +59685 +3143 @@ -22358,22 +24369,22 @@ 1 2 -91568 +43794 2 3 -9614 +4717 3 -8 -8664 +9 +4203 -8 -7691 -3029 +9 +7612 +1338 @@ -22389,22 +24400,22 @@ 1 2 -87393 +41733 2 3 -13978 +6603 3 -8 -8801 +7 +4101 -8 -19662 -2703 +7 +19179 +1616 @@ -22420,27 +24431,27 @@ 1 2 -75548 +35852 2 3 -14538 +6984 3 4 -8382 +4103 4 -10 -8762 +9 +4061 -10 -44512 -5645 +9 +44405 +3053 @@ -22456,12 +24467,12 @@ 1 2 -669961 +344231 2 -1367 -26832 +1207 +13514 @@ -22477,7 +24488,7 @@ 1 2 -696794 +357745 @@ -22493,12 +24504,12 @@ 1 2 -671827 +345048 2 -1367 -24966 +1207 +12697 @@ -22514,12 +24525,12 @@ 1 2 -686429 +352528 2 -1367 -10364 +1207 +5216 @@ -22529,15 +24540,15 @@ method_location -1280608 +622013 id -1116872 +549172 loc -40830 +15472 @@ -22551,17 +24562,17 @@ 1 2 -986500 +488331 2 3 -98235 +49469 3 119 -32136 +11371 @@ -22577,17 +24588,17 @@ 1 2 -36218 +13409 2 -51 -3078 +37 +1160 -51 -27729 -1534 +37 +23908 +902 @@ -22597,23 +24608,23 @@ constructors -277641 +138720 id -277641 +138720 name -133465 +68664 declaring_type_id -211980 +107588 unbound_id -223250 +114690 @@ -22627,7 +24638,7 @@ 1 2 -277641 +138720 @@ -22643,7 +24654,7 @@ 1 2 -277641 +138720 @@ -22659,7 +24670,7 @@ 1 2 -277641 +138720 @@ -22675,22 +24686,22 @@ 1 2 -102186 +52686 2 3 -19170 +9766 3 8 -10247 +5271 8 2183 -1860 +940 @@ -22706,17 +24717,17 @@ 1 2 -122482 +63031 2 11 -10082 +5181 11 2183 -901 +451 @@ -22732,22 +24743,22 @@ 1 2 -103067 +53132 2 3 -19326 +9846 3 10 -10087 +5179 10 2183 -983 +506 @@ -22763,17 +24774,17 @@ 1 2 -179312 +91484 2 3 -19750 +9914 3 20 -12916 +6189 @@ -22789,7 +24800,7 @@ 1 2 -211980 +107588 @@ -22805,17 +24816,17 @@ 1 2 -179312 +91484 2 3 -19750 +9914 3 20 -12916 +6189 @@ -22831,12 +24842,12 @@ 1 2 -220820 +113489 2 -780 -2430 +612 +1200 @@ -22852,7 +24863,7 @@ 1 2 -223250 +114690 @@ -22868,12 +24879,12 @@ 1 2 -220820 +113489 2 -780 -2430 +612 +1200 @@ -22883,15 +24894,15 @@ constructor_location -321369 +159509 id -277641 +138720 loc -24772 +10914 @@ -22905,17 +24916,17 @@ 1 2 -238320 +120137 2 3 -37640 +17760 3 87 -1680 +822 @@ -22931,22 +24942,22 @@ 1 2 -19000 +8122 2 3 -3180 +1484 3 -59 -1865 +38 +819 -59 -4796 -725 +38 +3935 +488 @@ -22956,23 +24967,23 @@ destructors -443 +225 id -443 +225 name -414 +213 declaring_type_id -443 +225 unbound_id -428 +220 @@ -22986,7 +24997,7 @@ 1 2 -443 +225 @@ -23002,7 +25013,7 @@ 1 2 -443 +225 @@ -23018,7 +25029,7 @@ 1 2 -443 +225 @@ -23034,12 +25045,12 @@ 1 2 -394 +203 2 4 -19 +10 @@ -23055,12 +25066,12 @@ 1 2 -394 +203 2 4 -19 +10 @@ -23076,12 +25087,12 @@ 1 2 -399 +205 2 3 -14 +7 @@ -23097,7 +25108,7 @@ 1 2 -443 +225 @@ -23113,7 +25124,7 @@ 1 2 -443 +225 @@ -23129,7 +25140,7 @@ 1 2 -443 +225 @@ -23145,12 +25156,12 @@ 1 2 -418 +218 -2 +3 4 -9 +2 @@ -23166,7 +25177,7 @@ 1 2 -428 +220 @@ -23182,12 +25193,12 @@ 1 2 -418 +218 -2 +3 4 -9 +2 @@ -23197,15 +25208,15 @@ destructor_location -662 +494 id -165 +125 loc -330 +230 @@ -23219,47 +25230,42 @@ 1 2 -32 +34 2 3 -44 +17 3 4 -9 +6 4 5 -16 +14 5 6 -6 +17 6 7 -29 +13 7 9 -12 +9 9 11 -12 - - -11 -12 -1 +10 @@ -23275,22 +25281,27 @@ 1 2 -260 +175 2 3 -19 +14 3 -5 -28 +4 +12 -5 -27 -21 +4 +9 +19 + + +9 +26 +8 @@ -23300,15 +25311,15 @@ overrides -273929 +140510 id -273905 +140498 base_id -65402 +33661 @@ -23322,12 +25333,12 @@ 1 2 -273881 +140485 2 3 -24 +12 @@ -23343,32 +25354,32 @@ 1 2 -40250 +20716 2 3 -10471 +5389 3 4 -4286 +2206 4 7 -5338 +2752 7 -184 -4909 +216 +2526 -215 -1329 -146 +217 +1317 +70 @@ -23378,15 +25389,15 @@ explicitly_implements -155943 +74568 id -155943 +74568 interface_id -13282 +6111 @@ -23400,7 +25411,7 @@ 1 2 -155943 +74568 @@ -23416,37 +25427,37 @@ 1 2 -6770 +3171 2 3 -2488 +1057 3 4 -1183 +604 4 5 -457 +210 5 7 -1207 +491 7 -58 -998 +41 +458 -58 +42 7851 -175 +117 @@ -23456,23 +25467,23 @@ local_functions -1801 +488 id -1801 +488 name -1034 +271 return_type -184 +47 unbound_id -1792 +488 @@ -23486,7 +25497,7 @@ 1 2 -1801 +488 @@ -23502,7 +25513,7 @@ 1 2 -1801 +488 @@ -23518,7 +25529,7 @@ 1 2 -1801 +488 @@ -23534,177 +25545,21 @@ 1 2 -892 +227 2 3 -80 +18 3 -137 -62 - - - - - - -name -return_type - - -12 - - -1 -2 -1026 +14 +22 -2 -4 -8 - - - - - - -name -unbound_id - - -12 - - -1 -2 -894 - - -2 -3 -82 - - -3 -137 -58 - - - - - - -return_type -id - - -12 - - -1 -2 -128 - - -2 -3 -29 - - -3 -7 -15 - - -7 -1134 -12 - - - - - - -return_type -name - - -12 - - -1 -2 -136 - - -2 -3 -25 - - -3 -9 -14 - - -9 -427 -9 - - - - - - -return_type -unbound_id - - -12 - - -1 -2 -128 - - -2 -3 -30 - - -3 -7 -14 - - -7 -1132 -12 - - - - - - -unbound_id -id - - -12 - - -1 -2 -1788 - - -3 -5 +14 +38 4 @@ -23712,6 +25567,177 @@ +name +return_type + + +12 + + +1 +2 +269 + + +2 +3 +2 + + + + + + +name +unbound_id + + +12 + + +1 +2 +227 + + +2 +3 +18 + + +3 +14 +22 + + +14 +38 +4 + + + + + + +return_type +id + + +12 + + +1 +2 +30 + + +2 +3 +7 + + +3 +4 +3 + + +4 +11 +4 + + +26 +336 +3 + + + + + + +return_type +name + + +12 + + +1 +2 +33 + + +2 +3 +7 + + +3 +6 +4 + + +26 +136 +3 + + + + + + +return_type +unbound_id + + +12 + + +1 +2 +30 + + +2 +3 +7 + + +3 +4 +3 + + +4 +11 +4 + + +26 +336 +3 + + + + + + +unbound_id +id + + +12 + + +1 +2 +488 + + + + + + unbound_id name @@ -23721,7 +25747,7 @@ 1 2 -1792 +488 @@ -23737,12 +25763,7 @@ 1 2 -1791 - - -3 -4 -1 +488 @@ -23752,15 +25773,15 @@ local_function_stmts -1792 +488 fn -1792 +488 stmt -1792 +488 @@ -23774,7 +25795,7 @@ 1 2 -1792 +488 @@ -23790,7 +25811,7 @@ 1 2 -1792 +488 @@ -23800,31 +25821,31 @@ fields -555686 +283465 id -555686 +283465 kind -9 +5 name -218219 +111604 declaring_type_id -103579 +52465 type_id -89512 +45611 unbound_id -547991 +279953 @@ -23838,7 +25859,7 @@ 1 2 -555686 +283465 @@ -23854,7 +25875,7 @@ 1 2 -555686 +283465 @@ -23870,7 +25891,7 @@ 1 2 -555686 +283465 @@ -23886,7 +25907,7 @@ 1 2 -555686 +283465 @@ -23902,7 +25923,7 @@ 1 2 -555686 +283465 @@ -23916,14 +25937,14 @@ 12 -38027 -38028 -4 +37974 +37975 +2 -76062 -76063 -4 +75103 +75104 +2 @@ -23937,14 +25958,14 @@ 12 -17662 -17663 -4 +17417 +17418 +2 -29062 -29063 -4 +29019 +29020 +2 @@ -23958,14 +25979,14 @@ 12 -3335 -3336 -4 +3310 +3311 +2 -18155 -18156 -4 +17817 +17818 +2 @@ -23981,12 +26002,12 @@ 2463 2464 -4 +2 -16366 -16367 -4 +16181 +16182 +2 @@ -24000,14 +26021,14 @@ 12 -38015 -38016 -4 +37962 +37963 +2 -74494 -74495 -4 +73714 +73715 +2 @@ -24023,131 +26044,131 @@ 1 2 -176171 +90218 2 3 -22565 - - -3 -14 -16555 - - -14 -4800 -2927 - - - - - - -name -kind - - -12 - - -1 -2 -208862 - - -2 -3 -9356 - - - - - - -name -declaring_type_id - - -12 - - -1 -2 -176195 - - -2 -3 -22551 - - -3 -14 -16545 - - -14 -4800 -2927 - - - - - - -name -type_id - - -12 - - -1 -2 -188678 - - -2 -3 -17656 - - -3 -2459 -11884 - - - - - - -name -unbound_id - - -12 - - -1 -2 -176560 - - -2 -3 -22570 +11538 3 15 -16472 +8500 15 4800 -2615 +1346 + + + + + + +name +kind + + +12 + + +1 +2 +106801 + + +2 +3 +4803 + + + + + + +name +declaring_type_id + + +12 + + +1 +2 +90231 + + +2 +3 +11531 + + +3 +15 +8498 + + +15 +4800 +1343 + + + + + + +name +type_id + + +12 + + +1 +2 +96495 + + +2 +3 +9032 + + +3 +2459 +6076 + + + + + + +name +unbound_id + + +12 + + +1 +2 +90406 + + +2 +3 +11536 + + +3 +16 +8412 + + +16 +4800 +1248 @@ -24163,42 +26184,42 @@ 1 2 -27319 +13760 2 3 -21148 +10719 3 4 -12571 +6297 4 5 -10101 +5139 5 6 -7934 +4061 6 8 -9273 +4712 8 12 -8148 +4143 12 4204 -7081 +3632 @@ -24214,12 +26235,12 @@ 1 2 -102488 +51969 2 3 -1091 +496 @@ -24235,42 +26256,42 @@ 1 2 -27319 +13760 2 3 -21153 +10721 3 4 -12575 +6299 4 5 -10096 +5136 5 6 -7934 +4061 6 8 -9278 +4715 8 12 -8148 +4143 12 4204 -7072 +3627 @@ -24286,37 +26307,37 @@ 1 2 -44527 +22594 2 3 -21201 +10699 3 4 -9434 +4720 4 5 -7364 +3742 5 6 -6161 +3141 6 -9 -9590 +8 +3675 -9 +8 132 -5299 +3893 @@ -24332,42 +26353,42 @@ 1 2 -27319 +13760 2 3 -21148 +10719 3 4 -12571 +6297 4 5 -10101 +5139 5 6 -7934 +4061 6 8 -9273 +4712 8 12 -8148 +4143 12 4204 -7081 +3632 @@ -24383,32 +26404,32 @@ 1 2 -55798 +28425 2 3 -10881 +5530 3 4 -6210 +3193 4 7 -7968 +4046 7 -27 -6789 +26 +3421 -27 -9290 -1865 +26 +9160 +995 @@ -24424,12 +26445,12 @@ 1 2 -87316 +44486 2 3 -2196 +1125 @@ -24445,27 +26466,27 @@ 1 2 -63727 +32473 2 3 -9317 +4712 3 5 -7885 +4020 5 -18 -6838 +17 +3436 -18 -5213 -1743 +17 +5144 +967 @@ -24481,22 +26502,22 @@ 1 2 -68310 +34857 2 3 -10038 +5091 3 7 -7232 +3680 7 -5746 -3930 +5706 +1982 @@ -24512,32 +26533,32 @@ 1 2 -55841 +28445 2 3 -11207 +5693 3 4 -5922 +3050 4 7 -7944 +4033 7 27 -6745 +3441 27 -9185 -1850 +9081 +947 @@ -24553,12 +26574,12 @@ 1 2 -547080 +279539 2 -234 -910 +210 +413 @@ -24574,7 +26595,7 @@ 1 2 -547991 +279953 @@ -24590,7 +26611,7 @@ 1 2 -547991 +279953 @@ -24606,12 +26627,12 @@ 1 2 -547080 +279539 2 -234 -910 +210 +413 @@ -24627,12 +26648,12 @@ 1 2 -547494 +279717 2 138 -496 +235 @@ -24642,15 +26663,15 @@ field_location -636442 +321998 id -548322 +279660 loc -52846 +24689 @@ -24664,17 +26685,17 @@ 1 2 -466217 +240001 2 3 -78095 +37935 3 57 -4008 +1722 @@ -24690,12 +26711,12 @@ 1 2 -49339 +23072 2 8882 -3506 +1616 @@ -24705,11 +26726,11 @@ localvars -163269 +72963 id -163269 +72963 kind @@ -24717,7 +26738,7 @@ name -22591 +9135 implicitly_typed @@ -24725,11 +26746,11 @@ type_id -7298 +3535 parent_id -163269 +72963 @@ -24743,7 +26764,7 @@ 1 2 -163269 +72963 @@ -24759,7 +26780,7 @@ 1 2 -163269 +72963 @@ -24775,7 +26796,7 @@ 1 2 -163269 +72963 @@ -24791,7 +26812,7 @@ 1 2 -163269 +72963 @@ -24807,7 +26828,7 @@ 1 2 -163269 +72963 @@ -24821,18 +26842,18 @@ 12 -18 -19 +3 +4 1 -799 -800 +373 +374 1 -162452 -162453 +72587 +72588 1 @@ -24847,18 +26868,18 @@ 12 -12 -13 +2 +3 1 -293 -294 +115 +116 1 -22378 -22379 +9057 +9058 1 @@ -24894,18 +26915,18 @@ 12 -10 -11 +2 +3 1 -25 -26 +8 +9 1 -7293 -7294 +3533 +3534 1 @@ -24920,18 +26941,18 @@ 12 -18 -19 +3 +4 1 -799 -800 +373 +374 1 -162452 -162453 +72587 +72588 1 @@ -24948,344 +26969,354 @@ 1 2 -14112 +5625 2 3 -3482 +1400 3 4 -1462 - - -4 -8 -1876 - - -8 -15750 -1659 - - - - - - -name -kind - - -12 - - -1 -2 -22499 - - -2 -3 -92 - - - - - - -name -implicitly_typed - - -12 - - -1 -2 -19931 - - -2 -3 -2660 - - - - - - -name -type_id - - -12 - - -1 -2 -19221 - - -2 -3 -1909 - - -3 -678 -1461 - - - - - - -name -parent_id - - -12 - - -1 -2 -14112 - - -2 -3 -3482 - - -3 -4 -1462 - - -4 -8 -1876 - - -8 -15750 -1659 - - - - - - -implicitly_typed -id - - -12 - - -36626 -36627 -1 - - -126643 -126644 -1 - - - - - - -implicitly_typed -kind - - -12 - - -1 -2 -1 - - -3 -4 -1 - - - - - - -implicitly_typed -name - - -12 - - -8549 -8550 -1 - - -16702 -16703 -1 - - - - - - -implicitly_typed -type_id - - -12 - - -2805 -2806 -1 - - -6179 -6180 -1 - - - - - - -implicitly_typed -parent_id - - -12 - - -36626 -36627 -1 - - -126643 -126644 -1 - - - - - - -type_id -id - - -12 - - -1 -2 -3308 - - -2 -3 -1138 - - -3 -4 -772 - - -4 -6 -624 - - -6 -11 -591 - - -11 -35 -548 - - -35 -37230 -317 - - - - - - -type_id -kind - - -12 - - -1 -2 -7269 - - -2 -4 -29 - - - - - - -type_id -name - - -12 - - -1 -2 -4172 - - -2 -3 -1328 - - -3 -4 -522 +559 4 7 -643 +690 + + +7 +46 +691 + + +46 +7564 +170 + + + + + + +name +kind + + +12 + + +1 +2 +9096 + + +2 +3 +39 + + + + + + +name +implicitly_typed + + +12 + + +1 +2 +8300 + + +2 +3 +835 + + + + + + +name +type_id + + +12 + + +1 +2 +7770 + + +2 +3 +727 + + +3 +494 +638 + + + + + + +name +parent_id + + +12 + + +1 +2 +5625 + + +2 +3 +1400 + + +3 +4 +559 + + +4 +7 +690 + + +7 +46 +691 + + +46 +7564 +170 + + + + + + +implicitly_typed +id + + +12 + + +13942 +13943 +1 + + +59021 +59022 +1 + + + + + + +implicitly_typed +kind + + +12 + + +1 +2 +1 + + +3 +4 +1 + + + + + + +implicitly_typed +name + + +12 + + +2512 +2513 +1 + + +7458 +7459 +1 + + + + + + +implicitly_typed +type_id + + +12 + + +1244 +1245 +1 + + +2982 +2983 +1 + + + + + + +implicitly_typed +parent_id + + +12 + + +13942 +13943 +1 + + +59021 +59022 +1 + + + + + + +type_id +id + + +12 + + +1 +2 +1585 + + +2 +3 +519 + + +3 +4 +460 + + +4 +6 +301 + + +6 +11 +279 + + +11 +47 +267 + + +47 +17427 +124 + + + + + + +type_id +kind + + +12 + + +1 +2 +3527 + + +2 +3 +8 + + + + + + +type_id +name + + +12 + + +1 +2 +1956 + + +2 +3 +733 + + +3 +4 +238 + + +4 +7 +310 7 49 -549 +266 -49 -1937 -84 +51 +900 +32 @@ -25301,12 +27332,12 @@ 1 2 -5612 +2844 2 3 -1686 +691 @@ -25322,37 +27353,37 @@ 1 2 -3308 +1585 2 3 -1138 +519 3 4 -772 +460 4 6 -624 +301 6 11 -591 +279 11 -35 -548 +47 +267 -35 -37230 -317 +47 +17427 +124 @@ -25368,7 +27399,7 @@ 1 2 -163269 +72963 @@ -25384,7 +27415,7 @@ 1 2 -163269 +72963 @@ -25400,7 +27431,7 @@ 1 2 -163269 +72963 @@ -25416,7 +27447,7 @@ 1 2 -163269 +72963 @@ -25432,7 +27463,7 @@ 1 2 -163269 +72963 @@ -25442,15 +27473,15 @@ localvar_location -163269 +72963 id -163269 +72963 loc -163189 +72932 @@ -25464,7 +27495,7 @@ 1 2 -163269 +72963 @@ -25480,12 +27511,12 @@ 1 2 -163109 +72901 2 3 -80 +31 @@ -25495,35 +27526,35 @@ params -2417684 +1189134 id -2417684 +1189134 name -80808 +41432 type_id -330575 +164897 index -199 +102 mode -29 +15 parent_id -1369834 +671887 unbound_id -1435188 +734670 @@ -25537,7 +27568,7 @@ 1 2 -2417684 +1189134 @@ -25553,7 +27584,7 @@ 1 2 -2417684 +1189134 @@ -25569,7 +27600,7 @@ 1 2 -2417684 +1189134 @@ -25585,7 +27616,7 @@ 1 2 -2417684 +1189134 @@ -25601,7 +27632,7 @@ 1 2 -2417684 +1189134 @@ -25617,7 +27648,7 @@ 1 2 -2417684 +1189134 @@ -25633,42 +27664,42 @@ 1 2 -31113 +15950 2 3 -13852 +7116 3 4 -7057 +3622 4 5 -4836 +2469 5 7 -6648 +3409 7 13 -6891 +3534 13 41 -6083 +3123 41 -46351 -4325 +45301 +2206 @@ -25684,22 +27715,22 @@ 1 2 -64209 +32939 2 3 -8158 +4178 3 12 -6171 +3153 12 -6855 -2269 +6754 +1160 @@ -25715,22 +27746,22 @@ 1 2 -55004 +28201 2 3 -14563 +7467 3 4 -5513 +2820 4 33 -5727 +2943 @@ -25746,12 +27777,12 @@ 1 2 -75777 +38848 2 7 -5031 +2584 @@ -25767,42 +27798,42 @@ 1 2 -31113 +15950 2 3 -13852 +7116 3 4 -7057 +3622 4 5 -4836 +2469 5 7 -6648 +3409 7 13 -6891 +3534 13 41 -6083 +3123 41 -46351 -4325 +45301 +2206 @@ -25818,42 +27849,42 @@ 1 2 -31503 +16151 2 3 -14081 +7222 3 4 -7072 +3639 4 5 -4953 +2519 5 7 -6477 +3324 7 13 -6906 +3544 13 43 -6156 +3158 43 -36753 -3657 +36702 +1872 @@ -25869,27 +27900,27 @@ 1 2 -227561 +114442 2 3 -38940 +19498 3 6 -30081 +14283 6 -24 -25059 +25 +12476 -24 -48953 -8932 +25 +47259 +4196 @@ -25905,17 +27936,17 @@ 1 2 -289087 +144619 2 4 -30490 +14880 4 -2470 -10997 +2452 +5397 @@ -25931,17 +27962,17 @@ 1 2 -292150 +146130 2 3 -25074 +12346 3 36 -13350 +6420 @@ -25957,12 +27988,12 @@ 1 2 -321866 +160670 2 5 -8708 +4226 @@ -25978,27 +28009,27 @@ 1 2 -230059 +115728 2 3 -36982 +18487 3 6 -30495 +14459 6 -25 -25020 +26 +12479 -25 -40410 -8017 +26 +38813 +3742 @@ -26014,27 +28045,27 @@ 1 2 -233250 +117385 2 3 -34903 +17404 3 5 -25741 +12270 5 -16 -25302 +17 +12554 -16 -33991 -11377 +17 +33727 +5281 @@ -26050,67 +28081,67 @@ 1 2 -24 +12 2 3 -14 +7 3 15 -14 +7 16 26 -14 +7 30 35 -14 +7 40 48 -14 +7 52 71 -14 +7 81 266 -14 +7 431 785 -14 +7 986 1520 -14 +7 1960 -3521 -14 +3510 +7 -5421 -21238 -14 +5391 +20664 +7 -47756 -281050 -14 +45851 +267875 +7 @@ -26126,72 +28157,72 @@ 1 2 -24 +12 2 3 -14 +7 3 10 -14 +7 12 14 -9 +5 17 20 -14 +7 20 22 -14 +7 23 27 -14 +7 29 46 -14 +7 55 66 -14 +7 86 143 -14 +7 202 435 -14 +7 630 -1620 -14 +1616 +7 -2712 -6835 -14 +2706 +6807 +7 -8088 -8089 -4 +8049 +8050 +2 @@ -26207,77 +28238,77 @@ 1 2 -24 +12 2 3 -14 +7 3 8 -9 +5 9 11 -14 +7 11 12 -9 +5 12 13 -9 +5 13 14 -9 +5 14 20 -14 +7 23 40 -14 +7 161 418 -14 +7 558 841 -14 +7 1010 1444 -14 +7 1705 -2798 -14 +2786 +7 -4226 -15732 -14 +4142 +15101 +7 -40518 -40519 -4 +38776 +38777 +2 @@ -26293,32 +28324,32 @@ 1 2 -92 +47 2 3 -43 +22 3 4 -14 +7 4 5 -14 +7 5 6 -29 +15 6 7 -4 +2 @@ -26334,67 +28365,67 @@ 1 2 -24 +12 2 3 -14 +7 3 15 -14 +7 16 26 -14 +7 30 35 -14 +7 40 48 -14 +7 52 71 -14 +7 81 266 -14 +7 431 785 -14 +7 986 1520 -14 +7 1960 -3521 -14 +3510 +7 -5421 -21238 -14 +5391 +20664 +7 -47756 -281050 -14 +45851 +267875 +7 @@ -26410,67 +28441,67 @@ 1 2 -24 +12 2 3 -14 +7 3 15 -14 +7 16 26 -14 +7 30 35 -14 +7 40 48 -14 +7 52 70 -14 +7 79 141 -14 +7 178 266 -14 +7 334 601 -14 +7 891 -2069 -14 +2068 +7 -3526 -13874 -14 +3523 +13842 +7 -29619 -168470 -14 +29502 +167307 +7 @@ -26486,32 +28517,32 @@ 1253 1254 -4 +2 -2019 -2020 -4 +2018 +2019 +2 -2345 -2346 -4 +2317 +2318 +2 -7103 -7104 -4 +6844 +6845 +2 -10553 -10554 -4 +10051 +10052 +2 -473106 -473107 -4 +451874 +451875 +2 @@ -26527,32 +28558,32 @@ 110 111 -4 +2 244 245 -4 +2 -283 -284 -4 +282 +283 +2 524 525 -4 +2 -1119 -1120 -4 +1118 +1119 +2 -15632 -15633 -4 +15568 +15569 +2 @@ -26568,32 +28599,32 @@ 227 228 -4 +2 -258 -259 -4 +257 +258 +2 -370 -371 -4 +358 +359 +2 -1224 -1225 -4 +1180 +1181 +2 -3184 -3185 -4 +3107 +3108 +2 -64542 -64543 -4 +62478 +62479 +2 @@ -26609,32 +28640,32 @@ 1 2 -4 +2 8 9 -4 +2 10 11 -4 +2 12 13 -4 +2 22 23 -4 +2 41 42 -4 +2 @@ -26650,32 +28681,32 @@ 1100 1101 -4 +2 -1881 -1882 -4 +1880 +1881 +2 -2345 -2346 -4 +2317 +2318 +2 -5653 -5654 -4 +5409 +5410 +2 -10553 -10554 -4 +10051 +10052 +2 -274248 -274249 -4 +261309 +261310 +2 @@ -26691,32 +28722,32 @@ 1167 1168 -4 +2 1568 1569 -4 +2 -1960 -1961 -4 +1959 +1960 +2 -6114 -6115 -4 +6113 +6114 +2 -8401 -8402 -4 +8393 +8394 +2 -275451 -275452 -4 +273867 +273868 +2 @@ -26732,27 +28763,27 @@ 1 2 -804742 +396310 2 3 -332635 +160705 3 4 -129188 +63147 4 -17 -102755 +15 +50643 -17 +15 42 -511 +1080 @@ -26768,27 +28799,27 @@ 1 2 -804742 +396310 2 3 -332635 +160705 3 4 -129188 +63147 4 -17 -102755 +15 +50643 -17 +15 42 -511 +1080 @@ -26804,22 +28835,22 @@ 1 2 -854291 +420682 2 3 -332932 +161091 3 4 -113276 +55521 4 23 -69333 +34591 @@ -26835,27 +28866,27 @@ 1 2 -804742 +396310 2 3 -332635 +160705 3 4 -129188 +63147 4 -17 -102755 +15 +50643 -17 +15 42 -511 +1080 @@ -26871,12 +28902,12 @@ 1 2 -1301328 +637849 2 4 -68505 +34037 @@ -26892,27 +28923,27 @@ 1 2 -804742 +396310 2 3 -332635 +160705 3 4 -129188 +63147 4 -17 -102755 +15 +50643 -17 +15 42 -511 +1080 @@ -26928,12 +28959,12 @@ 1 2 -1384908 +709316 2 -11328 -50279 +10857 +25354 @@ -26949,7 +28980,7 @@ 1 2 -1435188 +734670 @@ -26965,12 +28996,12 @@ 1 2 -1417084 +725656 2 -3718 -18104 +3610 +9014 @@ -26986,7 +29017,7 @@ 1 2 -1435188 +734670 @@ -27002,7 +29033,7 @@ 1 2 -1435188 +734670 @@ -27018,12 +29049,12 @@ 1 2 -1384908 +709316 2 -11328 -50279 +10857 +25354 @@ -27033,15 +29064,15 @@ param_location -2687352 +1316289 id -2413992 +1187548 loc -137537 +56062 @@ -27055,17 +29086,17 @@ 1 2 -2150827 +1063895 2 3 -256361 +120308 3 60 -6804 +3344 @@ -27081,12 +29112,12 @@ 1 2 -133216 +54295 2 -99581 -4320 +88836 +1767 @@ -27096,15 +29127,15 @@ statements -986473 +472277 id -986473 +472277 kind -38 +32 @@ -27118,7 +29149,7 @@ 1 2 -986473 +472277 @@ -27132,83 +29163,83 @@ 12 -57 -85 +15 +36 2 -97 -148 +48 +52 2 -204 -266 +58 +110 2 -283 -308 +139 +143 2 -312 -593 +146 +218 2 -790 -820 +366 +402 2 -918 -925 +470 +471 2 -1226 -1786 +490 +990 2 -2200 -2468 +1105 +1370 2 -2752 -3192 +1601 +1628 2 -3456 -3580 +1877 +1904 2 -5468 -8857 +2956 +5122 2 -18283 -60466 +10374 +32130 2 -62424 -75943 +37889 +48002 2 -94726 -191611 +48236 +97276 2 -246632 -246633 +151170 +151171 1 @@ -27219,19 +29250,19 @@ stmt_parent -814288 +370789 stmt -814288 +370789 index -450 +246 parent -431423 +204384 @@ -27245,7 +29276,7 @@ 1 2 -814288 +370789 @@ -27261,7 +29292,7 @@ 1 2 -814288 +370789 @@ -27277,62 +29308,57 @@ 1 2 -114 +35 2 -3 -44 +4 +14 -3 +4 5 -26 +45 5 -8 -33 +11 +19 -8 -9 -9 +11 +16 +15 -9 -10 -42 +16 +21 +22 -10 -26 -36 +21 +34 +19 -26 -45 -34 +37 +72 +19 -45 -95 -34 +78 +210 +19 -98 -472 -34 +229 +947 +19 -510 -78797 -34 - - -196051 -233226 -2 +1063 +135963 +16 @@ -27348,62 +29374,57 @@ 1 2 -114 +35 2 -3 -44 +4 +14 -3 +4 5 -26 +45 5 -8 -33 +11 +19 -8 -9 -9 +11 +16 +15 -9 -10 -42 +16 +21 +22 -10 -26 -36 +21 +34 +19 -26 -45 -34 +37 +72 +19 -45 -95 -34 +78 +210 +19 -98 -472 -34 +229 +947 +19 -510 -78797 -34 - - -196051 -233226 -2 +1063 +135963 +16 @@ -27419,22 +29440,22 @@ 1 2 -292109 +144057 2 3 -74655 +32560 3 5 -37594 +16168 5 -361 -27063 +233 +11597 @@ -27450,22 +29471,22 @@ 1 2 -292109 +144057 2 3 -74655 +32560 3 5 -37594 +16168 5 -361 -27063 +233 +11597 @@ -27475,11 +29496,11 @@ stmt_parent_top_level -172184 +101488 stmt -172184 +101488 index @@ -27487,7 +29508,7 @@ parent -126193 +83071 @@ -27501,7 +29522,7 @@ 1 2 -172184 +101488 @@ -27517,7 +29538,7 @@ 1 2 -172184 +101488 @@ -27531,8 +29552,8 @@ 12 -138041 -138042 +96009 +96010 1 @@ -27547,8 +29568,8 @@ 12 -101170 -101171 +78586 +78587 1 @@ -27565,17 +29586,17 @@ 1 2 -80853 +64837 2 3 -44695 +18049 3 -5 -643 +4 +183 @@ -27591,7 +29612,7 @@ 1 2 -126193 +83071 @@ -27601,15 +29622,15 @@ stmt_location -986473 +472277 id -986473 +472277 loc -983578 +470073 @@ -27623,7 +29644,7 @@ 1 2 -986473 +472277 @@ -27639,12 +29660,12 @@ 1 2 -980683 +467869 2 3 -2895 +2203 @@ -27654,15 +29675,15 @@ catch_type -3432 +1719 catch_id -3432 +1719 type_id -129 +79 kind @@ -27680,7 +29701,7 @@ 1 2 -3432 +1719 @@ -27696,7 +29717,7 @@ 1 2 -3432 +1719 @@ -27712,47 +29733,52 @@ 1 2 -32 +16 2 3 -22 +15 3 4 -11 +9 4 5 -12 +5 5 -8 -9 +7 +3 -8 -13 -11 +7 +9 +6 -13 -24 -9 +10 +15 +6 -27 -47 -9 +15 +28 +6 -48 -702 -9 +29 +144 +6 + + +203 +316 +3 @@ -27768,7 +29794,7 @@ 1 2 -129 +79 @@ -27782,13 +29808,13 @@ 12 -492 -493 +278 +279 1 -2260 -2261 +1349 +1350 1 @@ -27808,8 +29834,8 @@ 1 -103 -104 +74 +75 1 @@ -27820,19 +29846,19 @@ expressions -4249670 +1967906 id -4249670 +1967906 kind -404 +112 type_id -70297 +15377 @@ -27846,7 +29872,7 @@ 1 2 -4249670 +1967906 @@ -27862,7 +29888,7 @@ 1 2 -4249670 +1967906 @@ -27876,69 +29902,74 @@ 12 -1 -2 -19 +3 +17 +8 -2 -7 -34 +18 +61 +8 -7 -14 -34 +61 +134 +8 -16 -40 -29 +145 +243 +8 -41 -56 -34 +250 +457 +8 -58 -166 -34 +532 +643 +8 -166 -302 -34 +661 +1291 +8 -315 -813 -34 +1313 +2180 +8 -995 -1589 -34 +2252 +3767 +8 -3359 -9531 -34 +4681 +6580 +8 -10013 -21777 -34 +7133 +22007 +8 -28621 -87094 -34 +22297 +62473 +8 -94368 -127999 -14 +72642 +169972 +8 + + +174284 +252450 +2 @@ -27954,47 +29985,57 @@ 1 2 -155 +31 2 -3 -38 +4 +8 -3 -6 -34 +5 +8 +9 -7 -23 -34 +8 +16 +8 -25 -54 -34 +16 +37 +8 -63 -117 -34 +38 +71 +8 -252 -1822 -34 +77 +137 +8 -1908 -3347 -34 +137 +337 +8 -5303 -5304 -4 +384 +790 +8 + + +1764 +3948 +8 + + +4410 +7388 +3 @@ -28010,47 +30051,67 @@ 1 2 -12834 +2149 2 3 -21635 +1894 3 4 -3336 +786 4 5 -5596 +984 5 -7 -5606 +6 +970 -7 -11 -5591 +6 +8 +1167 -11 -20 -5537 +8 +12 +1337 -20 -51 -5309 +12 +19 +1299 -51 -139922 -4851 +19 +30 +1215 + + +30 +50 +1164 + + +50 +113 +1161 + + +113 +1379 +1154 + + +1383 +318203 +93 @@ -28066,27 +30127,42 @@ 1 2 -31181 +5687 2 3 -24937 +2551 3 4 -5270 +1979 4 +5 +1305 + + +5 6 -5104 +933 6 -34 -3803 +8 +1320 + + +8 +12 +1227 + + +12 +57 +372 @@ -28096,19 +30172,19 @@ expr_parent -3927027 +1745009 expr -3927027 +1745009 index -81755 +11825 parent -2575444 +1152644 @@ -28122,7 +30198,7 @@ 1 2 -3927027 +1745009 @@ -28138,7 +30214,7 @@ 1 2 -3927027 +1745009 @@ -28154,22 +30230,47 @@ 1 2 -67800 +3162 2 +3 +439 + + +3 +4 +1589 + + +4 +5 +186 + + +5 6 -6347 +1234 6 -13 -6188 +7 +2909 -13 -1585226 -1419 +8 +10 +1020 + + +10 +18 +895 + + +18 +837462 +387 @@ -28185,22 +30286,47 @@ 1 2 -67800 +3162 2 +3 +439 + + +3 +4 +1589 + + +4 +5 +186 + + +5 6 -6347 +1234 6 -13 -6188 +7 +2909 -13 -1585226 -1419 +8 +10 +1020 + + +10 +18 +895 + + +18 +837462 +387 @@ -28216,17 +30342,17 @@ 1 2 -1617409 +726174 2 3 -830338 +372615 3 -65537 -127696 +11185 +53853 @@ -28242,17 +30368,17 @@ 1 2 -1617409 +726174 2 3 -830338 +372615 3 -65537 -127696 +11185 +53853 @@ -28262,19 +30388,19 @@ expr_parent_top_level -499981 +239881 expr -499981 +239881 index -43 +22 parent -431797 +204873 @@ -28288,7 +30414,7 @@ 1 2 -499981 +239881 @@ -28304,7 +30430,7 @@ 1 2 -499981 +239881 @@ -28320,47 +30446,47 @@ 2 3 -4 +2 43 44 -4 +2 113 114 -4 +2 -166 -167 -4 +125 +126 +2 250 251 -4 +2 884 885 -4 +2 -4465 -4466 -4 +4456 +4457 +2 -8472 -8473 -4 +8335 +8336 +2 -88257 -88258 -4 +81483 +81484 +2 @@ -28376,47 +30502,47 @@ 2 3 -4 +2 43 44 -4 +2 113 114 -4 +2 -166 -167 -4 +125 +126 +2 250 251 -4 +2 884 885 -4 +2 -4465 -4466 -4 +4456 +4457 +2 -8472 -8473 -4 +8335 +8336 +2 -88193 -88194 -4 +81419 +81420 +2 @@ -28432,17 +30558,17 @@ 1 2 -391784 +184342 2 4 -35648 +18284 4 9 -4364 +2246 @@ -28458,17 +30584,17 @@ 1 2 -391964 +184435 2 4 -35526 +18222 4 9 -4305 +2216 @@ -28478,59 +30604,59 @@ implicitly_typed_array_creation -10813 +3866 id -10813 +3866 explicitly_sized_array_creation -4278 +1913 id -4278 +1913 stackalloc_array_creation -835 +170 id -835 +170 implicitly_typed_object_creation -769 +405 id -769 +405 mutator_invocation_mode -4 +2 id -4 +2 mode -4 +2 @@ -28544,7 +30670,7 @@ 1 2 -4 +2 @@ -28560,7 +30686,7 @@ 1 2 -4 +2 @@ -28570,26 +30696,26 @@ expr_compiler_generated -1629444 +759849 id -1629444 +759849 expr_value -1400280 +719515 id -1400280 +719515 value -102868 +52225 @@ -28603,7 +30729,7 @@ 1 2 -1400280 +719515 @@ -28619,27 +30745,27 @@ 1 2 -72296 +36487 2 3 -14943 +6531 3 -6 -7876 +5 +4017 -6 -2253 -7716 +5 +25 +3927 -2258 -272851 -37 +25 +148925 +1263 @@ -28649,15 +30775,15 @@ expr_call -677205 +304738 caller_id -677205 +304738 target_id -53764 +22603 @@ -28671,7 +30797,7 @@ 1 2 -677205 +304738 @@ -28687,32 +30813,32 @@ 1 2 -28802 +12775 2 3 -10037 +3512 3 4 -4351 +1884 4 7 -4653 +1846 7 24 -4065 +1714 24 -43831 -1856 +23696 +872 @@ -28722,15 +30848,15 @@ expr_access -1380403 +603781 accesser_id -1380403 +603781 target_id -339492 +151428 @@ -28744,7 +30870,7 @@ 1 2 -1380403 +603781 @@ -28760,37 +30886,37 @@ 1 2 -110513 +49895 2 3 -71310 +33117 3 4 -54805 +23450 4 5 -33178 +14681 5 6 -19897 +8746 6 -9 -25746 +10 +12743 -9 -7782 -24041 +10 +4570 +8794 @@ -28800,15 +30926,15 @@ expr_location -4249670 +1970785 id -4249670 +1970785 loc -3004477 +1481488 @@ -28822,7 +30948,7 @@ 1 2 -4249670 +1970785 @@ -28838,17 +30964,17 @@ 1 2 -2758234 +1266804 2 3 -241589 +207105 3 -542807 -4654 +62488 +7578 @@ -28858,15 +30984,15 @@ dynamic_member_name -13628 +6116 id -13628 +6116 name -1407 +629 @@ -28880,7 +31006,7 @@ 1 2 -13628 +6116 @@ -28896,47 +31022,47 @@ 1 2 -409 +172 2 3 -248 +107 3 4 -160 +82 4 5 -112 +50 5 7 -116 +47 7 11 -121 +50 11 -19 -107 +18 +50 -20 -97 -107 +18 +47 +50 -122 -304 -24 +70 +303 +17 @@ -28946,22 +31072,22 @@ conditional_access -3073 +1323 id -3073 +1323 expr_argument -873865 +409033 id -873865 +409033 mode @@ -28979,7 +31105,7 @@ 1 2 -873865 +409033 @@ -28993,23 +31119,23 @@ 12 -213 -214 +93 +94 1 -4293 -4294 +764 +765 1 -5670 -5671 +1980 +1981 1 -863689 -863690 +406196 +406197 1 @@ -29020,15 +31146,15 @@ expr_argument_name -60805 +27657 id -60805 +27657 name -2738 +1049 @@ -29042,7 +31168,7 @@ 1 2 -60805 +27657 @@ -29058,42 +31184,47 @@ 1 2 -895 +344 2 3 -486 +172 3 4 -281 +101 4 5 -195 +71 5 8 -251 +96 8 13 -232 +89 13 -28 -207 +26 +81 -28 -11230 -191 +26 +187 +79 + + +212 +4751 +16 @@ -29151,11 +31282,11 @@ xmlDTDs -6 +5 id -6 +5 root @@ -29171,7 +31302,7 @@ fileid -6 +5 @@ -29185,7 +31316,7 @@ 1 2 -6 +5 @@ -29201,7 +31332,7 @@ 1 2 -6 +5 @@ -29217,7 +31348,7 @@ 1 2 -6 +5 @@ -29233,7 +31364,7 @@ 1 2 -6 +5 @@ -29451,7 +31582,7 @@ 1 2 -6 +5 @@ -29467,7 +31598,7 @@ 1 2 -6 +5 @@ -29483,7 +31614,7 @@ 1 2 -6 +5 @@ -29499,7 +31630,7 @@ 1 2 -6 +5 @@ -33562,11 +35693,11 @@ commentline -420689 +94236 id -420689 +94236 kind @@ -33574,11 +35705,11 @@ text -201809 +52841 rawtext -204485 +53561 @@ -33592,7 +35723,7 @@ 1 2 -420689 +94236 @@ -33608,7 +35739,7 @@ 1 2 -420689 +94236 @@ -33624,7 +35755,7 @@ 1 2 -420689 +94236 @@ -33638,18 +35769,18 @@ 12 -18162 -18163 +604 +605 1 -151752 -151753 +7127 +7128 1 -167355 -167356 +81418 +81419 1 @@ -33664,18 +35795,18 @@ 12 -12037 -12038 +156 +157 1 -60681 -60682 +4531 +4532 1 -89979 -89980 +45654 +45655 1 @@ -33690,18 +35821,18 @@ 12 -12704 -12705 +157 +158 1 -60920 -60921 +4678 +4679 1 -90313 -90314 +45835 +45836 1 @@ -33718,17 +35849,17 @@ 1 2 -165358 +44757 2 3 -24053 +5919 3 -24462 -12397 +6105 +2164 @@ -33744,12 +35875,12 @@ 1 2 -200693 +52470 2 4 -1116 +371 @@ -33765,12 +35896,12 @@ 1 2 -199683 +52264 2 -51 -2126 +35 +577 @@ -33786,17 +35917,17 @@ 1 2 -168762 +45738 2 3 -23575 +5679 3 -24457 -12146 +5512 +2143 @@ -33812,7 +35943,7 @@ 1 2 -204485 +53561 @@ -33828,7 +35959,7 @@ 1 2 -204485 +53561 @@ -33838,15 +35969,15 @@ commentline_location -420689 +94236 id -420689 +94236 loc -420689 +94236 @@ -33860,7 +35991,7 @@ 1 2 -420689 +94236 @@ -33876,7 +36007,7 @@ 1 2 -420689 +94236 @@ -33886,26 +36017,26 @@ commentblock -147866 +42325 id -147866 +42325 commentblock_location -147866 +42325 id -147866 +42325 loc -147866 +42325 @@ -33919,7 +36050,7 @@ 1 2 -147866 +42325 @@ -33935,7 +36066,7 @@ 1 2 -147866 +42325 @@ -33945,15 +36076,15 @@ commentblock_binding -512139 +133597 id -147806 +42288 entity -221346 +65144 bindtype @@ -33971,22 +36102,22 @@ 1 2 -18500 +9049 2 3 -29767 +10673 3 4 -99239 +22336 4 7 -298 +228 @@ -34002,22 +36133,22 @@ 1 2 -13274 +7568 2 3 -5349 +1533 3 4 -29720 +10676 4 5 -99461 +22509 @@ -34033,17 +36164,17 @@ 1 2 -162214 +50257 2 3 -43096 +10921 3 -9895 -16035 +525 +3965 @@ -34059,22 +36190,22 @@ 1 2 -96638 +32218 2 3 -95048 +25063 3 4 -28767 +7689 4 5 -891 +173 @@ -34088,23 +36219,23 @@ 12 -83794 -83795 +23541 +23542 1 -104319 -104320 +32035 +32036 1 -107785 -107786 +32822 +32823 1 -113759 -113760 +37140 +37141 1 @@ -34119,23 +36250,23 @@ 12 -35897 -35898 +15869 +15870 1 -77379 -77380 +21711 +21712 1 -86313 -86314 +29111 +29112 1 -102338 -102339 +33686 +33687 1 @@ -34146,19 +36277,19 @@ commentblock_child -557212 +132682 id -147866 +42325 commentline -420600 +94161 index -5111 +1200 @@ -34172,32 +36303,22 @@ 1 2 -78789 +26814 2 3 -20407 +9030 3 -4 -19444 - - -4 5 -9185 +3555 5 -8 -11757 - - -8 -4098 -8281 +1136 +2923 @@ -34213,37 +36334,27 @@ 1 2 -4309 +2277 2 3 -75404 +24975 3 4 -22200 +8866 4 -5 -17648 - - -5 6 -8834 +3376 6 -9 -11470 - - -9 -4099 -7997 +1137 +2828 @@ -34259,12 +36370,7 @@ 1 2 -420592 - - -2 -3 -8 +94161 @@ -34280,12 +36386,12 @@ 1 2 -283998 +55641 2 3 -136602 +38520 @@ -34301,32 +36407,47 @@ 1 2 -2281 +286 2 -3 -1413 +6 +71 -3 +6 7 -407 +300 7 10 -450 +77 + + +10 +11 +145 11 -28 -389 +15 +64 -28 -118546 -169 +15 +17 +101 + + +17 +40 +99 + + +40 +40041 +53 @@ -34342,32 +36463,47 @@ 1 2 -2281 +286 2 -3 -1413 +6 +71 -3 +6 7 -407 +300 7 10 -450 +77 + + +10 +11 +145 11 -28 -389 +15 +64 -28 -118539 -169 +15 +17 +101 + + +17 +40 +99 + + +40 +40041 +53 @@ -34839,7 +36975,7 @@ name -2 +1 @@ -34867,13 +37003,8 @@ 12 -1 -2 -1 - - -2 -3 +3 +4 1 @@ -35171,7 +37302,7 @@ name -3 +6 @@ -35199,9 +37330,19 @@ 12 +1 +2 +4 + + +2 +3 +1 + + 3 4 -3 +1 @@ -35222,23 +37363,23 @@ cil_instruction -32160713 +16552562 id -32160713 +16552562 opcode -964 +496 index -332323 +171041 impl -1725702 +888189 @@ -35252,7 +37393,7 @@ 1 2 -32160713 +16552562 @@ -35268,7 +37409,7 @@ 1 2 -32160713 +16552562 @@ -35284,7 +37425,7 @@ 1 2 -32160713 +16552562 @@ -35300,72 +37441,72 @@ 1 7 -77 +40 7 42 -73 +37 46 106 -73 +37 128 302 -73 +37 304 953 -73 +37 1002 1752 -73 +37 1791 2952 -73 +37 3194 4898 -73 +37 5191 11577 -73 +37 11669 19719 -73 +37 19906 53412 -73 +37 54233 104298 -73 +37 104740 420483 -73 +37 562153 815024 -9 +5 @@ -35381,67 +37522,67 @@ 1 7 -82 +42 10 31 -73 +37 32 68 -73 +37 75 148 -73 +37 150 214 -73 +37 214 313 -77 +40 323 468 -73 +37 486 699 -73 +37 714 872 -73 +37 879 1176 -73 +37 1185 1360 -73 +37 1382 2349 -73 +37 2641 31606 -73 +37 @@ -35457,72 +37598,72 @@ 1 6 -77 +40 7 22 -73 +37 26 58 -73 +37 62 191 -73 +37 192 422 -73 +37 434 696 -73 +37 703 993 -73 +37 1012 2698 -73 +37 2754 5088 -73 +37 5150 9841 -73 +37 10112 16999 -73 +37 18955 42845 -73 +37 44005 171634 -73 +37 243198 301111 -9 +5 @@ -35538,22 +37679,22 @@ 1 2 -260306 +133975 2 11 -30587 +15742 11 25 -25483 +13115 25 354308 -15946 +8207 @@ -35569,27 +37710,27 @@ 1 2 -260900 +134281 2 3 -17675 +9097 3 5 -28722 +14782 5 160 -24927 +12829 160 169 -97 +50 @@ -35605,22 +37746,22 @@ 1 2 -260306 +133975 2 11 -30587 +15742 11 25 -25483 +13115 25 354308 -15946 +8207 @@ -35636,57 +37777,57 @@ 1 2 -83979 +43222 2 3 -251744 +129568 3 4 -332211 +170983 4 5 -195794 +100772 5 6 -107022 +55082 6 9 -157925 +81281 9 14 -150936 +77684 14 21 -133786 +68857 21 35 -131439 +67649 35 106 -129466 +66634 106 68231 -51395 +26452 @@ -35702,57 +37843,57 @@ 1 2 -83979 +43222 2 3 -252031 +129716 3 4 -338178 +174054 4 5 -239362 +123195 5 6 -132379 +68133 6 7 -96287 +49557 7 9 -147721 +76029 9 12 -128804 +66293 12 17 -135749 +69868 17 33 -132033 +67955 33 74 -39174 +20162 @@ -35768,57 +37909,57 @@ 1 2 -83979 +43222 2 3 -251744 +129568 3 4 -332211 +170983 4 5 -195794 +100772 5 6 -107022 +55082 6 9 -157925 +81281 9 14 -150936 +77684 14 21 -133786 +68857 21 35 -131439 +67649 35 106 -129466 +66634 106 68231 -51395 +26452 @@ -35828,15 +37969,15 @@ cil_jump -2003363 +1031096 instruction -2003363 +1031096 target -1604487 +825801 @@ -35850,7 +37991,7 @@ 1 2 -2003363 +1031096 @@ -35866,17 +38007,17 @@ 1 2 -1390890 +715866 2 3 -143683 +73951 3 360 -69913 +35983 @@ -35886,15 +38027,15 @@ cil_access -11925038 +6137610 instruction -11925038 +6137610 target -2664641 +1371444 @@ -35908,7 +38049,7 @@ 1 2 -11925038 +6137610 @@ -35924,37 +38065,37 @@ 1 2 -944943 +486346 2 3 -739982 +380856 3 4 -269054 +138477 4 5 -187125 +96310 5 7 -226689 +116673 7 14 -203539 +104758 14 25741 -93306 +48023 @@ -35964,15 +38105,15 @@ cil_value -1884013 +969669 instruction -1884013 +969669 value -494852 +254691 @@ -35986,7 +38127,7 @@ 1 2 -1884013 +969669 @@ -36002,27 +38143,27 @@ 1 2 -334369 +172094 2 3 -79006 +40663 3 6 -40708 +20952 6 33 -37250 +19172 33 86799 -3516 +1809 @@ -36032,19 +38173,19 @@ cil_switch -194401 +100055 instruction -23851 +12275 index -2518 +1296 target -130606 +67220 @@ -36058,47 +38199,47 @@ 3 4 -7018 +3612 4 5 -4593 +2363 5 6 -3229 +1662 6 7 -1685 +867 7 8 -1441 +742 8 11 -2157 +1110 11 17 -1845 +950 17 128 -1792 +922 141 518 -87 +45 @@ -36114,42 +38255,42 @@ 1 3 -1056 +543 3 4 -8245 +4244 4 5 -5489 +2825 5 6 -2571 +1323 6 7 -1841 +947 7 9 -1699 +874 9 14 -1797 +925 14 204 -1149 +591 @@ -36165,52 +38306,52 @@ 1 2 -24 +12 2 3 -988 +508 3 4 -48 +25 4 5 -360 +185 6 11 -204 +105 11 18 -204 +105 18 24 -189 +97 25 47 -199 +102 47 225 -189 +97 238 4898 -107 +55 @@ -36226,52 +38367,52 @@ 1 2 -38 +20 2 3 -974 +501 3 4 -97 +50 4 5 -311 +160 5 11 -204 +105 11 18 -209 +107 18 24 -204 +105 24 47 -194 +100 47 271 -189 +97 289 4830 -92 +47 @@ -36287,12 +38428,12 @@ 1 2 -128974 +66381 2 12 -1631 +839 @@ -36308,17 +38449,17 @@ 1 2 -118215 +60843 2 7 -9999 +5146 7 253 -2391 +1230 @@ -36396,15 +38537,15 @@ cil_type_location -277344 +142744 id -254973 +131230 loc -3414 +1757 @@ -36418,12 +38559,12 @@ 1 2 -232602 +119716 2 3 -22370 +11513 @@ -36439,67 +38580,67 @@ 1 2 -287 +147 2 4 -219 +112 4 6 -233 +120 6 9 -297 +152 9 13 -272 +140 13 17 -267 +137 17 23 -282 +145 23 32 -263 +135 32 43 -267 +137 43 66 -258 +132 66 110 -263 +135 112 238 -258 +132 239 2419 -243 +125 @@ -36509,15 +38650,15 @@ cil_method_location -1883969 +969646 id -1796560 +924658 loc -3126 +1609 @@ -36531,12 +38672,12 @@ 1 2 -1709152 +879671 2 3 -87408 +44987 @@ -36552,67 +38693,67 @@ 1 11 -258 +132 11 23 -243 +125 23 38 -243 +125 38 53 -253 +130 53 79 -238 +122 80 107 -238 +122 107 138 -248 +127 140 204 -243 +125 204 278 -238 +122 281 385 -238 +122 388 734 -238 +122 735 1631 -238 +122 1646 33686 -204 +105 @@ -36622,27 +38763,27 @@ cil_type -794772 +409055 id -794772 +409055 name -179044 +92151 kind -19 +10 parent -155427 +79995 sourceDecl -464615 +239129 @@ -36656,7 +38797,7 @@ 1 2 -794772 +409055 @@ -36672,7 +38813,7 @@ 1 2 -794772 +409055 @@ -36688,7 +38829,7 @@ 1 2 -794772 +409055 @@ -36704,7 +38845,7 @@ 1 2 -794772 +409055 @@ -36720,22 +38861,22 @@ 1 2 -137634 +70838 2 3 -22473 +11566 3 7 -14168 +7292 7 21324 -4768 +2454 @@ -36751,7 +38892,7 @@ 1 2 -179044 +92151 @@ -36767,17 +38908,17 @@ 1 2 -162396 +83582 2 4 -13642 +7021 4 21324 -3005 +1546 @@ -36793,17 +38934,17 @@ 1 2 -146094 +75192 2 3 -22497 +11579 3 21324 -10452 +5379 @@ -36819,22 +38960,22 @@ 123 124 -4 +2 2909 2910 -4 +2 37932 37933 -4 +2 122212 122213 -4 +2 @@ -36850,22 +38991,22 @@ 21 22 -4 +2 101 102 -4 +2 1188 1189 -4 +2 35450 35451 -4 +2 @@ -36881,22 +39022,22 @@ 1 2 -4 +2 31 32 -4 +2 11217 11218 -4 +2 21323 21324 -4 +2 @@ -36912,22 +39053,22 @@ 123 124 -4 +2 2464 2465 -4 +2 37932 37933 -4 +2 54872 54873 -4 +2 @@ -36943,27 +39084,27 @@ 1 2 -101776 +52382 2 3 -26793 +13790 3 6 -13340 +6866 6 33 -11699 +6021 33 26079 -1816 +935 @@ -36979,27 +39120,27 @@ 1 2 -102351 +52678 2 3 -27212 +14005 3 6 -13238 +6813 6 38 -11684 +6013 38 1426 -940 +483 @@ -37015,12 +39156,12 @@ 1 2 -152227 +78348 2 4 -3200 +1646 @@ -37036,27 +39177,27 @@ 1 2 -102249 +52625 2 3 -27231 +14015 3 6 -13145 +6765 6 38 -11665 +6003 38 3476 -1134 +584 @@ -37072,12 +39213,12 @@ 1 2 -437831 +225344 2 3705 -26783 +13785 @@ -37093,7 +39234,7 @@ 1 2 -464615 +239129 @@ -37109,7 +39250,7 @@ 1 2 -464615 +239129 @@ -37125,12 +39266,12 @@ 1 2 -456291 +234845 2 225 -8323 +4284 @@ -37140,15 +39281,15 @@ cil_pointer_type -599 +308 id -599 +308 pointee -599 +308 @@ -37162,7 +39303,7 @@ 1 2 -599 +308 @@ -37178,7 +39319,7 @@ 1 2 -599 +308 @@ -37188,19 +39329,19 @@ cil_array_type -14168 +7292 id -14168 +7292 element_type -14090 +7252 rank -14 +7 @@ -37214,7 +39355,7 @@ 1 2 -14168 +7292 @@ -37230,7 +39371,7 @@ 1 2 -14168 +7292 @@ -37246,12 +39387,12 @@ 1 2 -14017 +7214 2 4 -73 +37 @@ -37267,12 +39408,12 @@ 1 2 -14017 +7214 2 4 -73 +37 @@ -37288,17 +39429,17 @@ 1 2 -4 +2 16 17 -4 +2 2892 2893 -4 +2 @@ -37314,17 +39455,17 @@ 1 2 -4 +2 16 17 -4 +2 2892 2893 -4 +2 @@ -37387,23 +39528,23 @@ cil_method -2311748 +1189816 id -2311748 +1189816 name -439624 +226266 parent -379900 +195528 return_type -213850 +110065 @@ -37417,7 +39558,7 @@ 1 2 -2311748 +1189816 @@ -37433,7 +39574,7 @@ 1 2 -2311748 +1189816 @@ -37449,7 +39590,7 @@ 1 2 -2311748 +1189816 @@ -37465,27 +39606,27 @@ 1 2 -270861 +139407 2 3 -79561 +40949 3 4 -25020 +12877 4 7 -33475 +17229 7 64064 -30704 +15803 @@ -37501,27 +39642,27 @@ 1 2 -284864 +146614 2 3 -76522 +39384 3 5 -39846 +20508 5 25 -33139 +17056 25 52725 -5250 +2702 @@ -37537,17 +39678,17 @@ 1 2 -383884 +197578 2 4 -40207 +20693 4 2803 -15532 +7994 @@ -37563,42 +39704,42 @@ 1 2 -107909 +55538 2 3 -84456 +43468 3 4 -49919 +25692 4 5 -28551 +14695 5 7 -30850 +15878 7 11 -32896 +16931 11 21 -28936 +14893 21 3536 -16379 +8430 @@ -37614,42 +39755,42 @@ 1 2 -114294 +58825 2 3 -86609 +44576 3 4 -50474 +25978 4 5 -28897 +14873 5 7 -32852 +16908 7 11 -29993 +15437 11 26 -28673 +14757 26 1885 -8104 +4171 @@ -37665,32 +39806,32 @@ 1 2 -162060 +83409 2 3 -93633 +48191 3 4 -46363 +23862 4 5 -23281 +11982 5 7 -28376 +14604 7 1924 -26184 +13476 @@ -37706,27 +39847,27 @@ 1 2 -131882 +67877 2 3 -38215 +19668 3 5 -18829 +9691 5 13 -16555 +8520 13 190707 -8367 +4306 @@ -37742,22 +39883,22 @@ 1 2 -153439 +78972 2 3 -30324 +15607 3 6 -19131 +9846 6 28461 -10954 +5637 @@ -37773,22 +39914,22 @@ 1 2 -145296 +74781 2 3 -35365 +18202 3 5 -17539 +9027 5 62018 -15649 +8054 @@ -37798,15 +39939,15 @@ cil_method_source_declaration -2105637 +1083735 method -2105637 +1083735 source -1863186 +958949 @@ -37820,7 +39961,7 @@ 1 2 -2105637 +1083735 @@ -37836,12 +39977,12 @@ 1 2 -1758316 +904975 2 1021 -104869 +53974 @@ -37851,19 +39992,19 @@ cil_method_implementation -1725702 +888189 id -1725702 +888189 method -1638937 +843532 location -3092 +1591 @@ -37877,7 +40018,7 @@ 1 2 -1725702 +888189 @@ -37893,7 +40034,7 @@ 1 2 -1725702 +888189 @@ -37909,12 +40050,12 @@ 1 2 -1552171 +798875 2 3 -86765 +44656 @@ -37930,12 +40071,12 @@ 1 2 -1552171 +798875 2 3 -86765 +44656 @@ -37951,67 +40092,67 @@ 1 11 -272 +140 11 22 -238 +122 22 36 -238 +122 36 50 -233 +120 50 74 -243 +125 74 104 -248 +127 104 133 -238 +122 133 192 -233 +120 192 271 -233 +120 271 365 -248 +127 372 654 -233 +120 682 1597 -238 +122 1599 33053 -189 +97 @@ -38027,67 +40168,67 @@ 1 11 -272 +140 11 22 -238 +122 22 36 -238 +122 36 50 -233 +120 50 74 -243 +125 74 104 -248 +127 104 133 -238 +122 133 192 -233 +120 192 271 -233 +120 271 365 -248 +127 372 654 -233 +120 682 1597 -238 +122 1599 33053 -189 +97 @@ -38097,15 +40238,15 @@ cil_implements -107051 +55097 id -106292 +54706 decl -17719 +9119 @@ -38119,12 +40260,12 @@ 1 2 -105532 +54315 2 3 -759 +391 @@ -38140,27 +40281,27 @@ 1 2 -11533 +5936 2 3 -2703 +1391 3 5 -1578 +812 5 18 -1329 +684 18 2180 -574 +295 @@ -38170,23 +40311,23 @@ cil_field -1008310 +518960 id -1008310 +518960 parent -201113 +103509 name -360807 +185701 field_type -165835 +85352 @@ -38200,7 +40341,7 @@ 1 2 -1008310 +518960 @@ -38216,7 +40357,7 @@ 1 2 -1008310 +518960 @@ -38232,7 +40373,7 @@ 1 2 -1008310 +518960 @@ -38248,47 +40389,47 @@ 1 2 -60610 +31195 2 3 -41025 +21115 3 4 -22288 +11471 4 5 -15478 +7966 5 6 -11709 +6026 6 8 -16944 +8721 8 12 -17850 +9187 12 227 -15089 +7766 237 4205 -116 +60 @@ -38304,47 +40445,47 @@ 1 2 -60610 +31195 2 3 -41025 +21115 3 4 -22288 +11471 4 5 -15478 +7966 5 6 -11709 +6026 6 8 -16944 +8721 8 12 -17850 +9187 12 227 -15089 +7766 237 4205 -116 +60 @@ -38360,37 +40501,37 @@ 1 2 -70395 +36231 2 3 -59748 +30751 3 4 -20417 +10508 4 5 -11460 +5898 5 7 -15683 +8072 7 11 -16053 +8262 11 132 -7354 +3785 @@ -38406,22 +40547,22 @@ 1 2 -261811 +134749 2 3 -55345 +28485 3 7 -30066 +15474 7 5664 -13584 +6991 @@ -38437,22 +40578,22 @@ 1 2 -261811 +134749 2 3 -55345 +28485 3 7 -30066 +15474 7 5664 -13584 +6991 @@ -38468,17 +40609,17 @@ 1 2 -305355 +157161 2 3 -34050 +17525 3 2790 -21401 +11015 @@ -38494,32 +40635,32 @@ 1 2 -82606 +42515 2 3 -43757 +22521 3 4 -8957 +4610 4 7 -15254 +7851 7 31 -12537 +6452 31 21103 -2722 +1401 @@ -38535,22 +40676,22 @@ 1 2 -96682 +49760 2 3 -44483 +22894 3 6 -14227 +7322 6 12257 -10442 +5374 @@ -38566,27 +40707,27 @@ 1 2 -119793 +61655 2 3 -17958 +9242 3 5 -13238 +6813 5 20 -12463 +6414 20 8901 -2381 +1225 @@ -38596,23 +40737,23 @@ cil_parameter -4546452 +2339980 id -4546452 +2339980 parameterizable -2220248 +1142723 index -199 +102 param_type -552491 +284357 @@ -38626,7 +40767,7 @@ 1 2 -4546452 +2339980 @@ -38642,7 +40783,7 @@ 1 2 -4546452 +2339980 @@ -38658,7 +40799,7 @@ 1 2 -4546452 +2339980 @@ -38674,27 +40815,27 @@ 1 2 -900533 +463488 2 3 -787383 +405252 3 4 -324613 +167073 4 7 -174919 +90027 7 42 -32798 +16881 @@ -38710,27 +40851,27 @@ 1 2 -900533 +463488 2 3 -787383 +405252 3 4 -324613 +167073 4 7 -174919 +90027 7 42 -32798 +16881 @@ -38746,22 +40887,22 @@ 1 2 -948562 +488208 2 3 -797889 +410659 3 4 -312977 +161084 4 23 -160818 +82770 @@ -38777,67 +40918,67 @@ 1 2 -24 +12 2 3 -14 +7 3 18 -14 +7 20 35 -14 +7 44 53 -14 +7 61 78 -14 +7 87 122 -14 +7 150 293 -14 +7 378 632 -14 +7 810 2528 -14 +7 3263 6735 -14 +7 11503 42648 -14 +7 109294 455844 -14 +7 @@ -38853,67 +40994,67 @@ 1 2 -24 +12 2 3 -14 +7 3 18 -14 +7 20 35 -14 +7 44 53 -14 +7 61 78 -14 +7 87 122 -14 +7 150 293 -14 +7 378 632 -14 +7 810 2528 -14 +7 3263 6735 -14 +7 11503 42648 -14 +7 109294 455844 -14 +7 @@ -38929,72 +41070,72 @@ 1 2 -24 +12 2 3 -14 +7 3 11 -14 +7 11 16 -14 +7 16 18 -14 +7 19 21 -9 +5 22 28 -14 +7 34 88 -14 +7 129 233 -14 +7 290 447 -14 +7 554 928 -14 +7 1321 3323 -14 +7 6167 43422 -14 +7 83818 83819 -4 +2 @@ -39010,42 +41151,42 @@ 1 2 -185391 +95417 2 3 -137055 +70539 3 4 -45014 +23168 4 5 -38448 +19788 5 7 -43850 +22569 7 11 -42759 +22007 11 27 -41877 +21553 27 58010 -18094 +9312 @@ -39061,42 +41202,42 @@ 1 2 -188596 +97067 2 3 -135754 +69870 3 4 -45428 +23381 4 5 -37231 +19162 5 7 -44298 +22799 7 11 -42817 +22037 11 28 -41717 +21471 28 46068 -16647 +8568 @@ -39112,22 +41253,22 @@ 1 2 -385560 +198441 2 3 -109823 +56524 3 4 -44464 +22884 4 36 -12644 +6507 @@ -39137,37 +41278,37 @@ cil_parameter_in -32350 +16650 id -32350 +16650 cil_parameter_out -46022 +23687 id -46022 +23687 cil_setter -106754 +54944 prop -106754 +54944 method -106754 +54944 @@ -39181,7 +41322,7 @@ 1 2 -106754 +54944 @@ -39197,7 +41338,7 @@ 1 2 -106754 +54944 @@ -39207,19 +41348,19 @@ cil_custom_modifiers -4105 +2113 id -4105 +2113 modifier -53 +27 kind -4 +2 @@ -39233,7 +41374,7 @@ 1 2 -4105 +2113 @@ -39249,7 +41390,7 @@ 1 2 -4105 +2113 @@ -39265,57 +41406,57 @@ 5 6 -4 +2 10 11 -4 +2 11 12 -4 +2 19 20 -4 +2 25 26 -4 +2 29 30 -4 +2 51 52 -4 +2 68 69 -4 +2 87 88 -4 +2 94 95 -4 +2 444 445 -4 +2 @@ -39331,7 +41472,7 @@ 1 2 -53 +27 @@ -39347,7 +41488,7 @@ 843 844 -4 +2 @@ -39363,7 +41504,7 @@ 11 12 -4 +2 @@ -39373,15 +41514,15 @@ cil_type_annotation -196057 +100907 id -196057 +100907 annotation -4 +2 @@ -39395,7 +41536,7 @@ 1 2 -196057 +100907 @@ -39411,7 +41552,7 @@ 40253 40254 -4 +2 @@ -39421,15 +41562,15 @@ cil_getter -379350 +195244 prop -379350 +195244 method -379350 +195244 @@ -39443,7 +41584,7 @@ 1 2 -379350 +195244 @@ -39459,7 +41600,7 @@ 1 2 -379350 +195244 @@ -39469,15 +41610,15 @@ cil_adder -20870 +10741 event -20870 +10741 method -20870 +10741 @@ -39491,7 +41632,7 @@ 1 2 -20870 +10741 @@ -39507,7 +41648,7 @@ 1 2 -20870 +10741 @@ -39517,15 +41658,15 @@ cil_remover -20870 +10741 event -20870 +10741 method -20870 +10741 @@ -39539,7 +41680,7 @@ 1 2 -20870 +10741 @@ -39555,7 +41696,7 @@ 1 2 -20870 +10741 @@ -39613,23 +41754,23 @@ cil_property -379895 +195525 id -379895 +195525 parent -93647 +48198 name -106228 +54674 property_type -49821 +25642 @@ -39643,7 +41784,7 @@ 1 2 -379895 +195525 @@ -39659,7 +41800,7 @@ 1 2 -379895 +195525 @@ -39675,7 +41816,7 @@ 1 2 -379895 +195525 @@ -39691,42 +41832,42 @@ 1 2 -28863 +14855 2 3 -22273 +11463 3 4 -11411 +5873 4 5 -8450 +4349 5 6 -5737 +2953 6 9 -8660 +4457 9 25 -7096 +3652 25 1883 -1154 +594 @@ -39742,42 +41883,42 @@ 1 2 -33607 +17297 2 3 -17787 +9154 3 4 -11309 +5820 4 5 -8460 +4354 5 6 -5718 +2943 6 8 -6624 +3409 8 15 -7213 +3712 15 1883 -2927 +1506 @@ -39793,32 +41934,32 @@ 1 2 -35054 +18041 2 3 -25755 +13256 3 4 -13472 +6933 4 5 -8099 +4168 5 8 -7754 +3990 8 50 -3511 +1807 @@ -39834,27 +41975,27 @@ 1 2 -62626 +32232 2 3 -21430 +11030 3 4 -6477 +3334 4 8 -8757 +4507 8 2134 -6935 +3569 @@ -39870,27 +42011,27 @@ 1 2 -62626 +32232 2 3 -21503 +11067 3 4 -6453 +3321 4 8 -8772 +4514 8 1400 -6872 +3537 @@ -39906,17 +42047,17 @@ 1 2 -89400 +46012 2 3 -10968 +5645 3 568 -5859 +3015 @@ -39932,27 +42073,27 @@ 1 2 -31415 +16169 2 3 -7515 +3868 3 4 -3180 +1636 4 8 -4364 +2246 8 15452 -3346 +1722 @@ -39968,27 +42109,27 @@ 1 2 -33203 +17089 2 3 -7028 +3617 3 4 -3044 +1566 4 8 -3862 +1987 8 5858 -2683 +1381 @@ -40004,22 +42145,22 @@ 1 2 -39924 +20548 2 3 -5309 +2732 3 12 -3799 +1955 12 6253 -789 +406 @@ -40029,23 +42170,23 @@ cil_event -20841 +10726 id -20841 +10726 parent -6458 +3324 name -13063 +6723 event_type -6794 +3497 @@ -40059,7 +42200,7 @@ 1 2 -20841 +10726 @@ -40075,7 +42216,7 @@ 1 2 -20841 +10726 @@ -40091,7 +42232,7 @@ 1 2 -20841 +10726 @@ -40107,17 +42248,17 @@ 1 2 -5742 +2955 2 7 -491 +253 7 465 -224 +115 @@ -40133,17 +42274,17 @@ 1 2 -5742 +2955 2 7 -491 +253 7 465 -224 +115 @@ -40159,17 +42300,17 @@ 1 2 -5917 +3045 2 20 -487 +250 30 181 -53 +27 @@ -40185,162 +42326,162 @@ 1 2 -11655 +5998 2 4 -964 - - -4 -566 -443 - - - - - - -name -parent - - -12 - - -1 -2 -11655 - - -2 -4 -964 - - -4 -566 -443 - - - - - - -name -event_type - - -12 - - -1 -2 -12468 - - -2 -566 -594 - - - - - - -event_type -id - - -12 - - -1 -2 -944 - - -2 -3 -4515 - - -3 -4 -584 - - -4 -8 -574 - - -8 -318 -175 - - - - - - -event_type -parent - - -12 - - -1 -2 -1422 - - -2 -3 -5084 - - -3 -32 -287 - - - - - - -event_type -name - - -12 - - -1 -2 -1310 - - -2 -3 -4344 - - -3 -4 496 4 +566 +228 + + + + + + +name +parent + + +12 + + +1 +2 +5998 + + +2 +4 +496 + + +4 +566 +228 + + + + + + +name +event_type + + +12 + + +1 +2 +6417 + + +2 +566 +305 + + + + + + +event_type +id + + +12 + + +1 +2 +486 + + +2 +3 +2323 + + +3 +4 +300 + + +4 +8 +295 + + +8 +318 +90 + + + + + + +event_type +parent + + +12 + + +1 +2 +731 + + +2 +3 +2617 + + +3 +32 +147 + + + + + + +event_type +name + + +12 + + +1 +2 +674 + + +2 +3 +2236 + + +3 +4 +255 + + +4 10 -530 +273 10 243 -112 +57 @@ -40350,23 +42491,23 @@ cil_local_variable -1150606 +592197 id -1150606 +592197 impl -348611 +179424 index -691 +355 var_type -154214 +79371 @@ -40380,7 +42521,7 @@ 1 2 -1150606 +592197 @@ -40396,7 +42537,7 @@ 1 2 -1150606 +592197 @@ -40412,7 +42553,7 @@ 1 2 -1150606 +592197 @@ -40428,37 +42569,37 @@ 1 2 -139889 +71998 2 3 -62027 +31924 3 4 -49315 +25381 4 5 -23471 +12080 5 7 -31873 +16404 7 12 -28853 +14850 12 143 -13179 +6783 @@ -40474,37 +42615,37 @@ 1 2 -139889 +71998 2 3 -62027 +31924 3 4 -49315 +25381 4 5 -23471 +12080 5 7 -31873 +16404 7 12 -28853 +14850 12 143 -13179 +6783 @@ -40520,32 +42661,32 @@ 1 2 -168339 +86641 2 3 -70112 +36085 3 4 -37932 +19523 4 5 -20641 +10623 5 7 -27665 +14238 7 47 -23919 +12311 @@ -40561,62 +42702,62 @@ 1 2 -68 +35 2 3 -87 +45 3 5 -63 +32 5 7 -48 +25 7 8 -63 +32 8 13 -63 +32 13 19 -53 +27 21 51 -53 +27 56 167 -53 +27 182 829 -53 +27 1008 8631 -53 +27 11398 71575 -29 +15 @@ -40632,62 +42773,62 @@ 1 2 -68 +35 2 3 -87 +45 3 5 -63 +32 5 7 -48 +25 7 8 -63 +32 8 13 -63 +32 13 19 -53 +27 21 51 -53 +27 56 167 -53 +27 182 829 -53 +27 1008 8631 -53 +27 11398 71575 -29 +15 @@ -40703,67 +42844,67 @@ 1 2 -73 +37 2 3 -92 +47 3 4 -58 +30 4 5 -24 +12 5 6 -58 +30 6 8 -58 +30 8 11 -43 +22 11 18 -53 +27 19 42 -53 +27 52 110 -53 +27 143 539 -53 +27 599 4919 -53 +27 7226 19498 -14 +7 @@ -40779,37 +42920,37 @@ 1 2 -81286 +41836 2 3 -27236 +14018 3 4 -8372 +4309 4 5 -11821 +6084 5 8 -12785 +6580 8 76 -11572 +5956 76 35712 -1139 +586 @@ -40825,32 +42966,32 @@ 1 2 -85314 +43909 2 3 -30977 +15943 3 4 -8382 +4314 4 5 -11699 +6021 5 14 -12020 +6186 14 21451 -5820 +2995 @@ -40866,27 +43007,27 @@ 1 2 -96614 +49725 2 3 -28673 +14757 3 4 -13769 +7086 4 9 -11860 +6104 9 122 -3297 +1697 @@ -40949,35 +43090,35 @@ cil_handler -101450 +52214 id -101450 +52214 impl -71423 +36760 index -77 +40 kind -19 +10 try_start -97612 +50239 try_end -99828 +51380 handler_start -101450 +52214 @@ -40991,7 +43132,7 @@ 1 2 -101450 +52214 @@ -41007,7 +43148,7 @@ 1 2 -101450 +52214 @@ -41023,7 +43164,7 @@ 1 2 -101450 +52214 @@ -41039,7 +43180,7 @@ 1 2 -101450 +52214 @@ -41055,7 +43196,7 @@ 1 2 -101450 +52214 @@ -41071,7 +43212,7 @@ 1 2 -101450 +52214 @@ -41087,22 +43228,22 @@ 1 2 -53776 +27677 2 3 -11153 +5740 3 5 -5425 +2792 5 17 -1066 +548 @@ -41118,22 +43259,22 @@ 1 2 -53776 +27677 2 3 -11153 +5740 3 5 -5425 +2792 5 17 -1066 +548 @@ -41149,17 +43290,17 @@ 1 2 -61862 +31839 2 3 -9337 +4805 3 4 -224 +115 @@ -41175,22 +43316,22 @@ 1 2 -54804 +28206 2 3 -10846 +5582 3 7 -5528 +2845 7 15 -243 +125 @@ -41206,22 +43347,22 @@ 1 2 -54327 +27961 2 3 -11066 +5695 3 6 -5523 +2842 6 16 -506 +260 @@ -41237,22 +43378,22 @@ 1 2 -53776 +27677 2 3 -11153 +5740 3 5 -5425 +2792 5 17 -1066 +548 @@ -41268,77 +43409,77 @@ 1 2 -4 +2 2 3 -9 +5 4 5 -4 +2 9 10 -4 +2 11 12 -4 +2 20 21 -4 +2 27 28 -4 +2 40 41 -4 +2 66 67 -4 +2 123 124 -4 +2 219 220 -4 +2 685 686 -4 +2 1333 1334 -4 +2 3623 3624 -4 +2 14664 14665 -4 +2 @@ -41354,77 +43495,77 @@ 1 2 -4 +2 2 3 -9 +5 4 5 -4 +2 9 10 -4 +2 11 12 -4 +2 20 21 -4 +2 27 28 -4 +2 40 41 -4 +2 66 67 -4 +2 123 124 -4 +2 219 220 -4 +2 685 686 -4 +2 1333 1334 -4 +2 3623 3624 -4 +2 14664 14665 -4 +2 @@ -41440,22 +43581,22 @@ 1 2 -9 +5 2 3 -29 +15 3 4 -14 +7 4 5 -24 +12 @@ -41471,77 +43612,77 @@ 1 2 -4 +2 2 3 -9 +5 4 5 -4 +2 9 10 -4 +2 11 12 -4 +2 20 21 -4 +2 27 28 -4 +2 40 41 -4 +2 66 67 -4 +2 123 124 -4 +2 219 220 -4 +2 685 686 -4 +2 1333 1334 -4 +2 3623 3624 -4 +2 14664 14665 -4 +2 @@ -41557,77 +43698,77 @@ 1 2 -4 +2 2 3 -9 +5 4 5 -4 +2 9 10 -4 +2 11 12 -4 +2 20 21 -4 +2 27 28 -4 +2 40 41 -4 +2 66 67 -4 +2 123 124 -4 +2 219 220 -4 +2 685 686 -4 +2 1333 1334 -4 +2 3623 3624 -4 +2 14664 14665 -4 +2 @@ -41643,77 +43784,77 @@ 1 2 -4 +2 2 3 -9 +5 4 5 -4 +2 9 10 -4 +2 11 12 -4 +2 20 21 -4 +2 27 28 -4 +2 40 41 -4 +2 66 67 -4 +2 123 124 -4 +2 219 220 -4 +2 685 686 -4 +2 1333 1334 -4 +2 3623 3624 -4 +2 14664 14665 -4 +2 @@ -41729,22 +43870,22 @@ 166 167 -4 +2 302 303 -4 +2 8994 8995 -4 +2 11367 11368 -4 +2 @@ -41760,22 +43901,22 @@ 148 149 -4 +2 302 303 -4 +2 7560 7561 -4 +2 8663 8664 -4 +2 @@ -41791,22 +43932,22 @@ 5 6 -4 +2 8 9 -4 +2 14 15 -4 +2 16 17 -4 +2 @@ -41822,22 +43963,22 @@ 159 160 -4 +2 302 303 -4 +2 8695 8696 -4 +2 11363 11364 -4 +2 @@ -41853,22 +43994,22 @@ 159 160 -4 +2 302 303 -4 +2 8704 8705 -4 +2 11367 11368 -4 +2 @@ -41884,22 +44025,22 @@ 166 167 -4 +2 302 303 -4 +2 8994 8995 -4 +2 11367 11368 -4 +2 @@ -41915,12 +44056,12 @@ 1 2 -94315 +48542 2 8 -3297 +1697 @@ -41936,7 +44077,7 @@ 1 2 -97612 +50239 @@ -41952,12 +44093,12 @@ 1 2 -94315 +48542 2 8 -3297 +1697 @@ -41973,12 +44114,12 @@ 1 2 -95352 +49076 2 4 -2259 +1163 @@ -41994,12 +44135,12 @@ 1 2 -95396 +49098 2 3 -2216 +1140 @@ -42015,12 +44156,12 @@ 1 2 -94315 +48542 2 8 -3297 +1697 @@ -42036,12 +44177,12 @@ 1 2 -98601 +50748 2 7 -1227 +631 @@ -42057,7 +44198,7 @@ 1 2 -99828 +51380 @@ -42073,12 +44214,12 @@ 1 2 -98601 +50748 2 7 -1227 +631 @@ -42094,12 +44235,12 @@ 1 2 -99653 +51289 2 3 -175 +90 @@ -42115,7 +44256,7 @@ 1 2 -99828 +51380 @@ -42131,12 +44272,12 @@ 1 2 -98601 +50748 2 7 -1227 +631 @@ -42152,7 +44293,7 @@ 1 2 -101450 +52214 @@ -42168,7 +44309,7 @@ 1 2 -101450 +52214 @@ -42184,7 +44325,7 @@ 1 2 -101450 +52214 @@ -42200,7 +44341,7 @@ 1 2 -101450 +52214 @@ -42216,7 +44357,7 @@ 1 2 -101450 +52214 @@ -42232,7 +44373,7 @@ 1 2 -101450 +52214 @@ -42242,15 +44383,15 @@ cil_handler_filter -808 +416 id -808 +416 filter_start -808 +416 @@ -42264,7 +44405,7 @@ 1 2 -808 +416 @@ -42280,7 +44421,7 @@ 1 2 -808 +416 @@ -42290,15 +44431,15 @@ cil_handler_type -43806 +22546 id -43806 +22546 catch_type -1261 +649 @@ -42312,7 +44453,7 @@ 1 2 -43806 +22546 @@ -42328,42 +44469,42 @@ 1 2 -438 +225 2 3 -267 +137 3 4 -150 +77 4 5 -102 +52 5 8 -97 +50 8 16 -102 +52 16 2589 -97 +50 3495 3496 -4 +2 @@ -42373,15 +44514,15 @@ cil_method_stack_size -1725702 +888189 method -1725702 +888189 size -160 +82 @@ -42395,7 +44536,7 @@ 1 2 -1725702 +888189 @@ -42411,62 +44552,62 @@ 1 2 -9 +5 4 5 -9 +5 5 7 -14 +7 7 10 -14 +7 10 14 -14 +7 14 19 -14 +7 54 75 -14 +7 99 326 -14 +7 814 2665 -14 +7 3004 5050 -14 +7 8726 20803 -14 +7 23498 270374 -9 +5 @@ -42476,110 +44617,110 @@ cil_public -1909891 +982987 id -1909891 +982987 cil_private -928271 +477765 id -928271 +477765 cil_protected -1817300 +935332 id -1817300 +935332 cil_internal -41663 +23052 id -41663 +23052 cil_static -794484 +408907 id -794484 +408907 cil_sealed -356365 +183415 id -356365 +183415 cil_virtual -677238 +348562 id -677238 +348562 cil_abstract -165095 +84971 id -165095 +84971 cil_class -238432 +122717 id -238432 +122717 cil_interface -16540 +8513 id -16540 +8513 @@ -42608,37 +44749,37 @@ cil_specialname -810557 +417180 id -810557 +417180 cil_newslot -422046 +217219 id -422046 +217219 cil_base_class -235451 +121182 id -235451 +121182 base -21396 +11012 @@ -42652,7 +44793,7 @@ 1 2 -235451 +121182 @@ -42668,32 +44809,32 @@ 1 2 -12308 +6334 2 3 -3857 +1985 3 4 -1612 +829 4 7 -1889 +972 7 84 -1607 +827 86 23834 -121 +62 @@ -42703,15 +44844,15 @@ cil_base_interface -125136 +64405 id -68559 +35286 base -31176 +16046 @@ -42725,27 +44866,27 @@ 1 2 -47668 +24534 2 3 -8109 +4173 3 5 -6258 +3221 5 9 -5372 +2765 9 25 -1149 +591 @@ -42761,27 +44902,27 @@ 1 2 -22463 +11561 2 3 -3428 +1764 3 5 -2518 +1296 5 30 -2342 +1205 30 2180 -423 +218 @@ -42791,15 +44932,15 @@ cil_enum_underlying_type -14061 +7237 id -14061 +7237 underlying -38 +20 @@ -42813,7 +44954,7 @@ 1 2 -14061 +7237 @@ -42829,42 +44970,42 @@ 5 6 -4 +2 6 7 -4 +2 25 26 -4 +2 31 32 -4 +2 41 42 -4 +2 173 174 -4 +2 291 292 -4 +2 2315 2316 -4 +2 @@ -42874,19 +45015,19 @@ cil_type_parameter -184753 +95089 unbound -103856 +53453 index -102 +52 param -184753 +95089 @@ -42900,22 +45041,22 @@ 1 2 -74944 +38572 2 3 -18990 +9774 3 13 -8153 +4196 13 22 -1768 +909 @@ -42931,22 +45072,22 @@ 1 2 -74944 +38572 2 3 -18990 +9774 3 13 -8153 +4196 13 22 -1768 +909 @@ -42962,107 +45103,107 @@ 8 9 -4 +2 14 15 -4 +2 21 22 -4 +2 27 28 -4 +2 65 66 -4 +2 132 133 -4 +2 207 208 -4 +2 285 286 -4 +2 363 364 -4 +2 441 442 -4 +2 519 520 -4 +2 598 599 -4 +2 680 681 -4 +2 791 792 -4 +2 891 892 -4 +2 1012 1013 -4 +2 1173 1174 -4 +2 1409 1410 -4 +2 2037 2038 -4 +2 5936 5937 -4 +2 21323 21324 -4 +2 @@ -43078,107 +45219,107 @@ 8 9 -4 +2 14 15 -4 +2 21 22 -4 +2 27 28 -4 +2 65 66 -4 +2 132 133 -4 +2 207 208 -4 +2 285 286 -4 +2 363 364 -4 +2 441 442 -4 +2 519 520 -4 +2 598 599 -4 +2 680 681 -4 +2 791 792 -4 +2 891 892 -4 +2 1012 1013 -4 +2 1173 1174 -4 +2 1409 1410 -4 +2 2037 2038 -4 +2 5936 5937 -4 +2 21323 21324 -4 +2 @@ -43194,7 +45335,7 @@ 1 2 -184753 +95089 @@ -43210,7 +45351,7 @@ 1 2 -184753 +95089 @@ -43220,19 +45361,19 @@ cil_type_argument -736976 +379309 bound -481263 +247697 index -102 +52 t -252158 +129781 @@ -43246,17 +45387,17 @@ 1 2 -336123 +172996 2 3 -117338 +60392 3 22 -27801 +14309 @@ -43272,17 +45413,17 @@ 1 2 -341027 +175521 2 3 -115224 +59304 3 22 -25010 +12872 @@ -43298,97 +45439,97 @@ 3 4 -9 +5 4 5 -9 +5 84 85 -4 +2 205 206 -4 +2 343 344 -4 +2 482 483 -4 +2 621 622 -4 +2 760 761 -4 +2 899 900 -4 +2 1044 1045 -4 +2 1189 1190 -4 +2 1601 1602 -4 +2 1810 1811 -4 +2 2091 2092 -4 +2 2513 2514 -4 +2 3338 3339 -4 +2 5708 5709 -4 +2 29799 29800 -4 +2 98809 98810 -4 +2 @@ -43404,97 +45545,97 @@ 3 4 -14 +7 4 5 -4 +2 49 50 -4 +2 116 117 -4 +2 185 186 -4 +2 254 255 -4 +2 322 323 -4 +2 390 391 -4 +2 457 458 -4 +2 531 532 -4 +2 602 603 -4 +2 925 926 -4 +2 927 928 -4 +2 1083 1084 -4 +2 1307 1308 -4 +2 1645 1646 -4 +2 2968 2969 -4 +2 14488 14489 -4 +2 39680 39681 -4 +2 @@ -43510,27 +45651,27 @@ 1 2 -100301 +51623 2 3 -72738 +37437 3 4 -42481 +21864 4 6 -20101 +10345 6 4208 -16535 +8510 @@ -43546,17 +45687,17 @@ 1 2 -190773 +98187 2 3 -55476 +28552 3 20 -5908 +3040 @@ -43657,19 +45798,19 @@ cil_attribute -328261 +168950 attributeid -328261 +168950 element -248568 +127933 constructor -3375 +1737 @@ -43683,7 +45824,7 @@ 1 2 -328261 +168950 @@ -43699,7 +45840,7 @@ 1 2 -328261 +168950 @@ -43715,17 +45856,17 @@ 1 2 -197324 +101559 2 3 -36690 +18883 3 92 -14553 +7490 @@ -43741,17 +45882,17 @@ 1 2 -213178 +109719 2 3 -30991 +15950 3 7 -4398 +2263 @@ -43767,57 +45908,57 @@ 1 2 -555 +285 2 3 -399 +205 3 4 -287 +147 4 5 -316 +162 5 8 -306 +157 8 11 -263 +135 11 19 -267 +137 19 33 -258 +132 33 64 -253 +130 64 179 -253 +130 187 15289 -214 +110 @@ -43833,57 +45974,57 @@ 1 2 -599 +308 2 3 -384 +198 3 4 -282 +145 4 5 -316 +162 5 7 -243 +125 7 10 -282 +145 10 17 -253 +130 17 31 -263 +135 31 50 -258 +132 50 151 -253 +130 152 15028 -238 +122 @@ -43893,19 +46034,19 @@ cil_attribute_named_argument -10939 +7973 attribute_id -7978 +4938 param -155 +25 value -1095 +128 @@ -43919,17 +46060,17 @@ 1 2 -5089 +1911 2 3 -2815 +3020 3 4 -73 +7 @@ -43945,17 +46086,17 @@ 1 2 -6560 +3839 2 3 -1402 +1095 3 4 -14 +4 @@ -43971,67 +46112,62 @@ 1 2 -34 +3 2 -4 -9 - - -4 -5 -9 +3 +2 5 -6 -14 +7 +2 7 -8 -4 - - -8 9 -14 +2 -9 -11 -9 +11 +14 +2 14 -30 -9 +19 +2 -32 -43 -9 +19 +20 +1 -46 -47 -9 +22 +23 +2 -47 -48 -9 +26 +39 +2 -96 -308 -9 +55 +61 +2 -725 -731 -9 +347 +348 +2 + + +2859 +3660 +2 @@ -44047,37 +46183,42 @@ 1 2 -77 +8 2 3 -19 +5 3 4 -19 +2 4 -8 -9 +6 +2 -10 -14 -9 +6 +7 +1 + + +7 +8 +2 + + +9 +11 +2 26 -45 -9 - - -47 -56 -9 +39 +2 @@ -44093,22 +46234,32 @@ 1 2 -720 +71 2 3 -238 +25 3 -5 -82 +4 +6 -5 -866 -53 +4 +7 +11 + + +8 +301 +10 + + +347 +3871 +3 @@ -44124,12 +46275,12 @@ 1 2 -1066 +120 2 -10 -29 +7 +8 @@ -44139,19 +46290,19 @@ cil_attribute_positional_argument -103140 +58735 attribute_id -97018 +57269 index -29 +5 value -17261 +4430 @@ -44165,12 +46316,12 @@ 1 2 -92337 +55901 2 -7 -4680 +6 +1368 @@ -44186,12 +46337,12 @@ 1 2 -92347 +55905 2 -7 -4670 +5 +1364 @@ -44205,34 +46356,29 @@ 12 -14 -15 -4 +20 +21 +1 -24 -25 -4 +21 +22 +1 -117 -118 -4 +57 +58 +1 -141 -142 -4 +1368 +1369 +1 -961 -962 -4 - - -19919 -19920 -4 +57269 +57270 +1 @@ -44246,29 +46392,24 @@ 12 -4 -5 -4 +3 +4 +2 5 6 -9 +1 -25 -26 -4 +110 +111 +1 -433 -434 -4 - - -3150 -3151 -4 +4331 +4332 +1 @@ -44284,22 +46425,27 @@ 1 2 -12298 +2894 2 3 -2527 +723 3 -6 -1446 +4 +215 -6 -5556 -988 +4 +9 +382 + + +9 +17524 +216 @@ -44315,12 +46461,12 @@ 1 2 -16935 +4414 2 6 -326 +16 @@ -44330,19 +46476,19 @@ metadata_handle -6175093 +3178070 entity -5685301 +2925983 location -3414 +1757 handle -274022 +141034 @@ -44356,17 +46502,17 @@ 1 2 -5213687 +2683251 2 3 -462599 +238091 3 638 -9015 +4640 @@ -44382,12 +46528,12 @@ 1 2 -5445549 +2802586 2 59 -239752 +123396 @@ -44403,72 +46549,72 @@ 1 3 -287 +147 3 36 -258 +132 36 79 -267 +137 79 130 -258 +132 130 200 -258 +132 200 288 -258 +132 288 400 -258 +132 403 527 -258 +132 528 744 -258 +132 747 1109 -263 +135 1116 1915 -258 +132 1920 4051 -258 +132 4053 50922 -258 +132 67370 92454 -14 +7 @@ -44484,67 +46630,67 @@ 1 2 -287 +147 3 20 -282 +145 20 46 -267 +137 46 76 -263 +135 77 119 -258 +132 119 176 -258 +132 176 253 -258 +132 255 332 -263 +135 338 481 -258 +132 483 683 -258 +132 685 1273 -258 +132 1295 2685 -258 +132 2710 55264 -243 +125 @@ -44560,62 +46706,62 @@ 1 2 -18927 +9741 2 3 -45004 +23163 3 5 -23905 +12303 5 6 -17505 +9009 6 7 -30124 +15504 7 9 -18966 +9761 9 11 -22078 +11363 11 13 -21026 +10822 13 21 -21455 +11042 21 39 -21119 +10869 39 83 -20563 +10583 83 -1062 -13345 +1061 +6868 @@ -44631,52 +46777,52 @@ 1 2 -62879 +32363 2 3 -21085 +10852 3 4 -46967 +24173 4 5 -18927 +9741 5 6 -19390 +9979 6 7 -22054 +11350 7 11 -23281 +11982 11 19 -21986 +11315 19 41 -20846 +10729 41 702 -16604 +8545 From 7068a265a69e287d474ad5b661f2ea114e7b0514 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 3 Feb 2021 11:01:16 +0100 Subject: [PATCH 137/429] Fix XML comment processing --- csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs | 2 +- .../Semmle.Extraction.CSharp/Populators/CommentPopulator.cs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index 75db5c0e951..f9e0d7c3806 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -393,7 +393,7 @@ namespace Semmle.Extraction.CSharp } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { - extractor.Message(new Message("Unhandled exception processing syntax tree", tree.FilePath, null, ex.StackTrace)); + extractor.Message(new Message($"Unhandled exception processing syntax tree. {ex.Message}", tree.FilePath, null, ex.StackTrace)); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs index 0574a11db5f..325746274ff 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CommentPopulator.cs @@ -117,10 +117,6 @@ namespace Semmle.Extraction.CSharp.Populators currentLocation = nextLineLocation; } break; - // Strangely, these are reported as SingleLineCommentTrivia. - case SyntaxKind.DocumentationCommentExteriorTrivia: - cx.ModelError($"Unhandled comment type {trivia.Kind()} for {trivia}"); - break; } } } From 88d1539d43e0e707e3e1a92abadbb06e46b0f1a1 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 4 Feb 2021 08:39:43 +0100 Subject: [PATCH 138/429] Fix file read error log message --- csharp/extractor/Semmle.Extraction/Entities/File.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs index 72d0ea8e986..4c339e49f7b 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/File.cs @@ -62,7 +62,7 @@ namespace Semmle.Extraction.Entities } catch (Exception exc) { - Context.ExtractionError($"Couldn't read file", originalPath, null, exc.StackTrace); + Context.ExtractionError($"Couldn't read file: {originalPath}", null, null, exc.StackTrace); } } From 543f5916c4605b37a107aa95c052195793682023 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 4 Feb 2021 08:49:19 +0100 Subject: [PATCH 139/429] Fix expected test AST --- csharp/ql/test/library-tests/comments/PrintAst.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/test/library-tests/comments/PrintAst.expected b/csharp/ql/test/library-tests/comments/PrintAst.expected index eeb7993eaef..71d16cdf134 100644 --- a/csharp/ql/test/library-tests/comments/PrintAst.expected +++ b/csharp/ql/test/library-tests/comments/PrintAst.expected @@ -38,7 +38,7 @@ comments2.cs: # 34| 0: [LocalVariableAccess] access to local variable z # 34| 1: [IntLiteral] 0 # 40| 8: [Class] C3 -# 48| 9: [IndexerProperty] S1 +# 48| 9: [Property] S1 # 48| -1: [TypeMention] string # 52| 3: [Getter] get_S1 # 52| 4: [BlockStmt] {...} From 7087904637a30be28fc6ffac17beb85cc20e666c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 3 Feb 2021 19:37:57 +0000 Subject: [PATCH 140/429] C++: Solution. --- cpp/ql/src/semmle/code/cpp/commons/Printf.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll index cf230beb8d2..8d9ad5c77e4 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Printf.qll @@ -53,7 +53,12 @@ predicate primitiveVariadicFormatter( ( if type = "" then outputParamIndex = -1 else outputParamIndex = 0 // Conveniently, these buffer parameters are all at index 0. ) and - not exists(f.getBlock()) // exclude functions with an implementation in the snapshot as they may not be standard implementations. + not ( + // exclude functions with an implementation in the snapshot source + // directory, as they may not be standard implementations. + exists(f.getBlock()) and + exists(f.getFile().getRelativePath()) + ) } private predicate callsVariadicFormatter( From 47ab9ba81b5aa29016a239b3cddbdef999fcb21e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 11:16:27 +0100 Subject: [PATCH 141/429] C++: emplace and emplace_back takes its arguments by universal references, so they should also specify flow as indirections. --- .../semmle/code/cpp/models/implementations/StdContainer.qll | 4 ++-- cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll index 7a38ede5fc6..e7abde30e8c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -193,7 +193,7 @@ class StdVectorEmplace extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter except the position iterator to qualifier and return value // (here we assume taint flow from any constructor parameter to the constructed object) - input.isParameter([1 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([1 .. getNumberOfParameters() - 1]) and ( output.isQualifierObject() or output.isReturnValue() @@ -210,7 +210,7 @@ class StdVectorEmplaceBack extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier // (here we assume taint flow from any constructor parameter to the constructed object) - input.isParameter([0 .. getNumberOfParameters() - 1]) and + input.isParameterDeref([0 .. getNumberOfParameters() - 1]) and output.isQualifierObject() } } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp index 7e7fc8176ce..ec354da548c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -491,8 +491,8 @@ void test_vector_emplace() { std::vector v1(10), v2(10); v1.emplace_back(source()); - sink(v1); // $ ast MISSING: ir + sink(v1); // $ ast,ir v2.emplace(v2.begin(), source()); - sink(v2); // $ ast MISSING: ir + sink(v2); // $ ast,ir } From 55615586eed1a4162aeff56e2d0b0bb53e64e0c9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 11:30:44 +0100 Subject: [PATCH 142/429] C++: Address review comments. --- cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll | 3 --- 1 file changed, 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll index bf6430e548b..f4a80cbabac 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strset.qll @@ -40,9 +40,6 @@ private class StrsetFunction extends ArrayFunction, DataFlowFunction, AliasFunct // flow from the input string to the output string input.isParameter(0) and output.isReturnValue() - or - input.isParameterDeref(0) and - output.isReturnValueDeref() } override predicate parameterNeverEscapes(int index) { none() } From b77dd54618411876efcaff99f78b121a4de8e164 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 19:24:27 +0100 Subject: [PATCH 143/429] implement basic map get/set for immutable.js --- javascript/ql/src/javascript.qll | 1 + .../javascript/dataflow/Configuration.qll | 8 +- .../javascript/frameworks/Immutable.qll | 100 ++++++++++++++++++ .../frameworks/Immutable/immutable.js | 15 +++ .../frameworks/Immutable/tests.expected | 5 + .../frameworks/Immutable/tests.ql | 18 ++++ 6 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Immutable.qll create mode 100644 javascript/ql/test/library-tests/frameworks/Immutable/immutable.js create mode 100644 javascript/ql/test/library-tests/frameworks/Immutable/tests.expected create mode 100644 javascript/ql/test/library-tests/frameworks/Immutable/tests.ql diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 9cc8e112b5b..d5c459c4d5c 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -85,6 +85,7 @@ import semmle.javascript.frameworks.Electron import semmle.javascript.frameworks.EventEmitter import semmle.javascript.frameworks.Files import semmle.javascript.frameworks.Firebase +import semmle.javascript.frameworks.Immutable import semmle.javascript.frameworks.jQuery import semmle.javascript.frameworks.JWT import semmle.javascript.frameworks.Handlebars diff --git a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll index def92d07fe3..609dddf2a4b 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Configuration.qll @@ -659,9 +659,15 @@ module PseudoProperties { */ pragma[inline] string mapValueKnownKey(DataFlow::Node key) { - result = pseudoProperty("mapValue", any(string s | key.mayHaveStringValue(s))) + result = mapValueKey(any(string s | key.mayHaveStringValue(s))) } + /** + * Gets a pseudo-property for the location of a map value where the key is `key`. + */ + bindingset[key] + string mapValueKey(string key) { result = pseudoProperty("mapValue", key) } + /** * Gets a pseudo-property for the location of a map value where the key is `key`. */ diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll new file mode 100644 index 00000000000..7d6add1609d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -0,0 +1,100 @@ +/** + * Provides classes and predicates for reasoning about [immutable](https://www.npmjs.com/package/immutable). + */ + +import javascript + +/** + * Provides classes implementing data-flow for Immutable. + */ +private module Immutable { + private import DataFlow::PseudoProperties + + /** + * An API entrypoint for the global `Immutable` variable. + */ + private class ImmutableGlobalEntry extends API::EntryPoint { + ImmutableGlobalEntry() { this = "ImmutableGlobalEntry" } + + override DataFlow::SourceNode getAUse() { result = DataFlow::globalVarRef("Immutable") } + + override DataFlow::Node getARhs() { none() } + } + + /** + * An import of the `Immutable` library. + */ + API::Node immutableImport() { + result = API::moduleImport("immutable") + or + result = API::root().getASuccessor(any(ImmutableGlobalEntry i)) + } + + /** + * An instance of an immutable map. + */ + API::Node immutableMap() { + result = immutableImport().getMember("Map").getReturn() + or + result = immutableMap().getMember("set").getReturn() + } + + /** + * Gets the immutable collection where `pred` has been stored using the pseudoproperty `prop`. + */ + DataFlow::SourceNode storeStep(DataFlow::Node pred, string prop) { + exists(DataFlow::CallNode call, string key | + call = immutableImport().getMember("Map").getACall() + | + prop = mapValueKey(key) and + pred = call.getOptionArgument(0, key) and + result = call + ) + // TODO: map set. + } + + /** + * Gets the value that was stored in the immutable collection `pred` under the pseudoproperty `prop`. + */ + DataFlow::Node loadStep(DataFlow::Node pred, string prop) { + // map.get() + exists(DataFlow::MethodCallNode call | call = immutableMap().getMember("get").getACall() | + pred = call.getReceiver() and + result = call and + prop = mapValue(call.getArgument(0)) + ) + } + + /** + * Gets an immutable collection that contains all the elements from `pred`. + */ + DataFlow::Node step(DataFlow::Node pred) { + // map.set() copies all existing values + exists(DataFlow::CallNode call | call = immutableMap().getMember("set").getACall() | + pred = call.getReceiver() and + result = call + ) + } + + /** + * A dataflow step for an immutable collection. + */ + class ImmutableConstructionStep extends DataFlow::AdditionalFlowStep { + ImmutableConstructionStep() { this = [loadStep(_, _), storeStep(_, _), step(_)] } + + override predicate loadStep(DataFlow::Node pred, DataFlow::Node succ, string prop) { + this = loadStep(pred, prop) and + succ = this + } + + override predicate storeStep(DataFlow::Node pred, DataFlow::SourceNode succ, string prop) { + this = storeStep(pred, prop) and + succ = this + } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + this = step(pred) and + succ = this + } + } +} diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js new file mode 100644 index 00000000000..6e11ed0b9e8 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -0,0 +1,15 @@ +var obj = { a: source("a"), b: source("b1") }; +sink(obj["a"]); // NOT OK + +const { Map } = require('immutable'); + +const map1 = Map(obj); + +sink(map1.get("b")); // NOT OK + +const map2 = map1.set('c', "safe"); +sink(map1.get("a")); // NOT OK +sink(map2.get("a")); // NOT OK +sink(map2.get("b")); // OK - but still flagged [INCONSISTENCY] + + diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected new file mode 100644 index 00000000000..d71fe8e504c --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -0,0 +1,5 @@ +| immutable.js:1:16:1:26 | source("a") | immutable.js:2:6:2:13 | obj["a"] | +| immutable.js:1:16:1:26 | source("a") | immutable.js:11:6:11:18 | map1.get("a") | +| immutable.js:1:16:1:26 | source("a") | immutable.js:12:6:12:18 | map2.get("a") | +| immutable.js:1:32:1:43 | source("b1") | immutable.js:8:6:8:18 | map1.get("b") | +| immutable.js:1:32:1:43 | source("b1") | immutable.js:13:6:13:18 | map2.get("b") | diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.ql b/javascript/ql/test/library-tests/frameworks/Immutable/tests.ql new file mode 100644 index 00000000000..58d12ea774f --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.ql @@ -0,0 +1,18 @@ +import javascript +private import semmle.javascript.dataflow.internal.StepSummary + +class Config extends DataFlow::Configuration { + Config() { this = "Config" } + + override predicate isSource(DataFlow::Node source) { + source.(DataFlow::CallNode).getCalleeName() = "source" + } + + override predicate isSink(DataFlow::Node sink) { + exists(DataFlow::CallNode call | call.getCalleeName() = "sink" | call.getAnArgument() = sink) + } +} + +query predicate dataFlow(DataFlow::Node pred, DataFlow::Node succ) { + any(Config c).hasFlow(pred, succ) +} From b1f092f052768c142c5f7e9c489dbebf08948c93 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 19:39:12 +0100 Subject: [PATCH 144/429] add support for map.set in Immutable model --- .../ql/src/semmle/javascript/frameworks/Immutable.qll | 7 ++++++- .../test/library-tests/frameworks/Immutable/immutable.js | 4 +++- .../test/library-tests/frameworks/Immutable/tests.expected | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index 7d6add1609d..c02c5b3c958 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -50,7 +50,12 @@ private module Immutable { pred = call.getOptionArgument(0, key) and result = call ) - // TODO: map set. + or + exists(DataFlow::CallNode call | call = immutableMap().getMember("set").getACall() | + prop = mapValue(call.getArgument(0)) and + pred = call.getArgument(1) and + result = call + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index 6e11ed0b9e8..fd8dfab69b7 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -12,4 +12,6 @@ sink(map1.get("a")); // NOT OK sink(map2.get("a")); // NOT OK sink(map2.get("b")); // OK - but still flagged [INCONSISTENCY] - +const map3 = map2.set("d", source("d")); +sink(map1.get("d")); // OK +sink(map3.get("d")); // NOT OK diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index d71fe8e504c..fdc6e454e8b 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -3,3 +3,4 @@ | immutable.js:1:16:1:26 | source("a") | immutable.js:12:6:12:18 | map2.get("a") | | immutable.js:1:32:1:43 | source("b1") | immutable.js:8:6:8:18 | map1.get("b") | | immutable.js:1:32:1:43 | source("b1") | immutable.js:13:6:13:18 | map2.get("b") | +| immutable.js:15:28:15:38 | source("d") | immutable.js:17:6:17:18 | map3.get("d") | From 6cbe4caeccfcd39d1745cd8e5656adee8641345f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 19:46:16 +0100 Subject: [PATCH 145/429] support toJS() by using plain property names instead of pseudoproperties. --- .../javascript/frameworks/Immutable.qll | 30 +++++++++++-------- .../frameworks/Immutable/immutable.js | 3 ++ .../frameworks/Immutable/tests.expected | 1 + 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index c02c5b3c958..ac849ff7300 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -8,8 +8,6 @@ import javascript * Provides classes implementing data-flow for Immutable. */ private module Immutable { - private import DataFlow::PseudoProperties - /** * An API entrypoint for the global `Immutable` variable. */ @@ -40,33 +38,35 @@ private module Immutable { } /** - * Gets the immutable collection where `pred` has been stored using the pseudoproperty `prop`. + * An instance of any immutable collection. + */ + API::Node immutableCollection() { result = immutableMap() } + + /** + * Gets the immutable collection where `pred` has been stored using the name `prop`. */ DataFlow::SourceNode storeStep(DataFlow::Node pred, string prop) { - exists(DataFlow::CallNode call, string key | - call = immutableImport().getMember("Map").getACall() - | - prop = mapValueKey(key) and - pred = call.getOptionArgument(0, key) and + exists(DataFlow::CallNode call | call = immutableImport().getMember("Map").getACall() | + pred = call.getOptionArgument(0, prop) and result = call ) or exists(DataFlow::CallNode call | call = immutableMap().getMember("set").getACall() | - prop = mapValue(call.getArgument(0)) and + call.getArgument(0).mayHaveStringValue(prop) and pred = call.getArgument(1) and result = call ) } /** - * Gets the value that was stored in the immutable collection `pred` under the pseudoproperty `prop`. + * Gets the value that was stored in the immutable collection `pred` under the name `prop`. */ DataFlow::Node loadStep(DataFlow::Node pred, string prop) { // map.get() exists(DataFlow::MethodCallNode call | call = immutableMap().getMember("get").getACall() | + call.getArgument(0).mayHaveStringValue(prop) and pred = call.getReceiver() and - result = call and - prop = mapValue(call.getArgument(0)) + result = call ) } @@ -79,6 +79,12 @@ private module Immutable { pred = call.getReceiver() and result = call ) + or + // toJS() or any immutable collection converts it to a plain JavaScript object/array. + exists(DataFlow::CallNode call | call = immutableCollection().getMember("toJS").getACall() | + pred = call.getReceiver() and + result = call + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index fd8dfab69b7..c7a5741e812 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -15,3 +15,6 @@ sink(map2.get("b")); // OK - but still flagged [INCONSISTENCY] const map3 = map2.set("d", source("d")); sink(map1.get("d")); // OK sink(map3.get("d")); // NOT OK + + +sink(map3.toJS()["a"]); // NOT OK \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index fdc6e454e8b..94827bb5316 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -1,6 +1,7 @@ | immutable.js:1:16:1:26 | source("a") | immutable.js:2:6:2:13 | obj["a"] | | immutable.js:1:16:1:26 | source("a") | immutable.js:11:6:11:18 | map1.get("a") | | immutable.js:1:16:1:26 | source("a") | immutable.js:12:6:12:18 | map2.get("a") | +| immutable.js:1:16:1:26 | source("a") | immutable.js:20:6:20:21 | map3.toJS()["a"] | | immutable.js:1:32:1:43 | source("b1") | immutable.js:8:6:8:18 | map1.get("b") | | immutable.js:1:32:1:43 | source("b1") | immutable.js:13:6:13:18 | map2.get("b") | | immutable.js:15:28:15:38 | source("d") | immutable.js:17:6:17:18 | map3.get("d") | From a5c9492c872c7b4dfe74d7dc7f8a723819978be7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Feb 2021 20:28:48 +0100 Subject: [PATCH 146/429] add support for fromJS in the Immutable model --- .../javascript/frameworks/Immutable.qll | 31 +++++++++---------- .../frameworks/Immutable/immutable.js | 6 ++-- .../frameworks/Immutable/tests.expected | 1 + 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index ac849ff7300..b8cd8146b6d 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -28,30 +28,27 @@ private module Immutable { result = API::root().getASuccessor(any(ImmutableGlobalEntry i)) } - /** - * An instance of an immutable map. - */ - API::Node immutableMap() { - result = immutableImport().getMember("Map").getReturn() - or - result = immutableMap().getMember("set").getReturn() - } - /** * An instance of any immutable collection. */ - API::Node immutableCollection() { result = immutableMap() } + API::Node immutableCollection() { + result = immutableImport().getMember(["Map", "fromJS"]).getReturn() + or + result.getAnImmediateUse() = step(immutableCollection().getAUse()) + } /** * Gets the immutable collection where `pred` has been stored using the name `prop`. */ DataFlow::SourceNode storeStep(DataFlow::Node pred, string prop) { - exists(DataFlow::CallNode call | call = immutableImport().getMember("Map").getACall() | + exists(DataFlow::CallNode call | + call = immutableImport().getMember(["Map", "fromJS"]).getACall() + | pred = call.getOptionArgument(0, prop) and result = call ) or - exists(DataFlow::CallNode call | call = immutableMap().getMember("set").getACall() | + exists(DataFlow::CallNode call | call = immutableCollection().getMember("set").getACall() | call.getArgument(0).mayHaveStringValue(prop) and pred = call.getArgument(1) and result = call @@ -63,7 +60,9 @@ private module Immutable { */ DataFlow::Node loadStep(DataFlow::Node pred, string prop) { // map.get() - exists(DataFlow::MethodCallNode call | call = immutableMap().getMember("get").getACall() | + exists(DataFlow::MethodCallNode call | + call = immutableCollection().getMember("get").getACall() + | call.getArgument(0).mayHaveStringValue(prop) and pred = call.getReceiver() and result = call @@ -73,14 +72,14 @@ private module Immutable { /** * Gets an immutable collection that contains all the elements from `pred`. */ - DataFlow::Node step(DataFlow::Node pred) { + DataFlow::SourceNode step(DataFlow::Node pred) { // map.set() copies all existing values - exists(DataFlow::CallNode call | call = immutableMap().getMember("set").getACall() | + exists(DataFlow::CallNode call | call = immutableCollection().getMember("set").getACall() | pred = call.getReceiver() and result = call ) or - // toJS() or any immutable collection converts it to a plain JavaScript object/array. + // toJS() or any immutable collection converts it to a plain JavaScript object/array (and vice versa for `fromJS`). exists(DataFlow::CallNode call | call = immutableCollection().getMember("toJS").getACall() | pred = call.getReceiver() and result = call diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index c7a5741e812..2f3bf2fd495 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -1,7 +1,7 @@ var obj = { a: source("a"), b: source("b1") }; sink(obj["a"]); // NOT OK -const { Map } = require('immutable'); +const { Map, fromJS } = require('immutable'); const map1 = Map(obj); @@ -17,4 +17,6 @@ sink(map1.get("d")); // OK sink(map3.get("d")); // NOT OK -sink(map3.toJS()["a"]); // NOT OK \ No newline at end of file +sink(map3.toJS()["a"]); // NOT OK + +sink(fromJS({"e": source("e")}).get("e")); // NOT OK \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index 94827bb5316..23d217ac4b3 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -5,3 +5,4 @@ | immutable.js:1:32:1:43 | source("b1") | immutable.js:8:6:8:18 | map1.get("b") | | immutable.js:1:32:1:43 | source("b1") | immutable.js:13:6:13:18 | map2.get("b") | | immutable.js:15:28:15:38 | source("d") | immutable.js:17:6:17:18 | map3.get("d") | +| immutable.js:22:19:22:29 | source("e") | immutable.js:22:6:22:40 | fromJS( ... et("e") | From 2e7bf9b53c69dad33b30afe97a1a50467186eae0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 10:54:41 +0100 Subject: [PATCH 147/429] implement Immutable lists --- .../javascript/frameworks/Immutable.qll | 40 ++++++++++++++++--- .../frameworks/Immutable/immutable.js | 15 ++++++- .../frameworks/Immutable/tests.expected | 4 ++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index b8cd8146b6d..a0468f6843a 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -6,6 +6,8 @@ import javascript /** * Provides classes implementing data-flow for Immutable. + * + * The implemention rely on the flowsteps implemented in `Collections.qll`. */ private module Immutable { /** @@ -32,15 +34,17 @@ private module Immutable { * An instance of any immutable collection. */ API::Node immutableCollection() { - result = immutableImport().getMember(["Map", "fromJS"]).getReturn() + // keep this list in sync with the constructors defined in `storeStep`. + result = immutableImport().getMember(["Map", "List", "fromJS"]).getReturn() or - result.getAnImmediateUse() = step(immutableCollection().getAUse()) + result = immutableCollection().getMember(["set", "map", "filter", "push"]).getReturn() } /** * Gets the immutable collection where `pred` has been stored using the name `prop`. */ DataFlow::SourceNode storeStep(DataFlow::Node pred, string prop) { + // Immutable.Map() and Immutable.fromJS(). exists(DataFlow::CallNode call | call = immutableImport().getMember(["Map", "fromJS"]).getACall() | @@ -48,11 +52,31 @@ private module Immutable { result = call ) or + // Immutable.List() + exists(DataFlow::CallNode call, DataFlow::ArrayCreationNode arr | + call = immutableImport().getMember("List").getACall() + | + arr = call.getArgument(0).getALocalSource() and + exists(int i | + prop = DataFlow::PseudoProperties::arrayElement(i) and + pred = arr.getElement(i) and + result = call + ) + ) + or + // collection.set(key, value) exists(DataFlow::CallNode call | call = immutableCollection().getMember("set").getACall() | call.getArgument(0).mayHaveStringValue(prop) and pred = call.getArgument(1) and result = call ) + or + // list.push(x) + exists(DataFlow::CallNode call | call = immutableCollection().getMember("push").getACall() | + pred = call.getArgument(0) and + result = call and + prop = DataFlow::PseudoProperties::arrayElement() + ) } /** @@ -73,14 +97,18 @@ private module Immutable { * Gets an immutable collection that contains all the elements from `pred`. */ DataFlow::SourceNode step(DataFlow::Node pred) { - // map.set() copies all existing values - exists(DataFlow::CallNode call | call = immutableCollection().getMember("set").getACall() | + // map.set() / list.push() copies all existing values + exists(DataFlow::CallNode call | + call = immutableCollection().getMember(["set", "push"]).getACall() + | pred = call.getReceiver() and result = call ) or - // toJS() or any immutable collection converts it to a plain JavaScript object/array (and vice versa for `fromJS`). - exists(DataFlow::CallNode call | call = immutableCollection().getMember("toJS").getACall() | + // toJS()/toList() on any immutable collection converts it to a plain JavaScript object/array (and vice versa for `fromJS`). + exists(DataFlow::CallNode call | + call = immutableCollection().getMember(["toJS", "toList"]).getACall() + | pred = call.getReceiver() and result = call ) diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index 2f3bf2fd495..68bf67b76d6 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -1,7 +1,7 @@ var obj = { a: source("a"), b: source("b1") }; sink(obj["a"]); // NOT OK -const { Map, fromJS } = require('immutable'); +const { Map, fromJS, List } = require('immutable'); const map1 = Map(obj); @@ -19,4 +19,15 @@ sink(map3.get("d")); // NOT OK sink(map3.toJS()["a"]); // NOT OK -sink(fromJS({"e": source("e")}).get("e")); // NOT OK \ No newline at end of file +sink(fromJS({"e": source("e")}).get("e")); // NOT OK + +const l1 = List([source(), "foobar"]); +l1.forEach(x => sink(x)); // NOT OK + +l1.map(x => "safe").forEach(x => sink(x)); // OK + +List(["safe"]).map(x => source()).forEach(x => sink(x)); // NOT OK + +List([source()]).map(x => x).filter(x => true).toList().forEach(x => sink(x)); // NOT OK + +List(["safe"]).push(source()).forEach(x => sink(x)); // NOT OK diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index 23d217ac4b3..f5080effdc2 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -6,3 +6,7 @@ | immutable.js:1:32:1:43 | source("b1") | immutable.js:13:6:13:18 | map2.get("b") | | immutable.js:15:28:15:38 | source("d") | immutable.js:17:6:17:18 | map3.get("d") | | immutable.js:22:19:22:29 | source("e") | immutable.js:22:6:22:40 | fromJS( ... et("e") | +| immutable.js:24:18:24:25 | source() | immutable.js:25:22:25:22 | x | +| immutable.js:29:25:29:32 | source() | immutable.js:29:53:29:53 | x | +| immutable.js:31:7:31:14 | source() | immutable.js:31:75:31:75 | x | +| immutable.js:33:21:33:28 | source() | immutable.js:33:49:33:49 | x | From 609b16b1f77c7f0913ff97f4e526925110a408e4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 11:02:50 +0100 Subject: [PATCH 148/429] implement Immutable OrderedMap --- .../ql/src/semmle/javascript/frameworks/Immutable.qll | 4 ++-- .../ql/test/library-tests/frameworks/Immutable/immutable.js | 6 +++++- .../test/library-tests/frameworks/Immutable/tests.expected | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index a0468f6843a..28e05f7f0e2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -35,7 +35,7 @@ private module Immutable { */ API::Node immutableCollection() { // keep this list in sync with the constructors defined in `storeStep`. - result = immutableImport().getMember(["Map", "List", "fromJS"]).getReturn() + result = immutableImport().getMember(["Map", "OrderedMap", "List", "fromJS"]).getReturn() or result = immutableCollection().getMember(["set", "map", "filter", "push"]).getReturn() } @@ -46,7 +46,7 @@ private module Immutable { DataFlow::SourceNode storeStep(DataFlow::Node pred, string prop) { // Immutable.Map() and Immutable.fromJS(). exists(DataFlow::CallNode call | - call = immutableImport().getMember(["Map", "fromJS"]).getACall() + call = immutableImport().getMember(["Map", "OrderedMap", "fromJS"]).getACall() | pred = call.getOptionArgument(0, prop) and result = call diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index 68bf67b76d6..0b62c174039 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -1,7 +1,7 @@ var obj = { a: source("a"), b: source("b1") }; sink(obj["a"]); // NOT OK -const { Map, fromJS, List } = require('immutable'); +const { Map, fromJS, List, OrderedMap } = require('immutable'); const map1 = Map(obj); @@ -31,3 +31,7 @@ List(["safe"]).map(x => source()).forEach(x => sink(x)); // NOT OK List([source()]).map(x => x).filter(x => true).toList().forEach(x => sink(x)); // NOT OK List(["safe"]).push(source()).forEach(x => sink(x)); // NOT OK + + +const map4 = OrderedMap({}).set("f", source()); +sink(map4.get("f")); // NOT OK \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index f5080effdc2..de0b333cba9 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -10,3 +10,4 @@ | immutable.js:29:25:29:32 | source() | immutable.js:29:53:29:53 | x | | immutable.js:31:7:31:14 | source() | immutable.js:31:75:31:75 | x | | immutable.js:33:21:33:28 | source() | immutable.js:33:49:33:49 | x | +| immutable.js:36:38:36:45 | source() | immutable.js:37:6:37:18 | map4.get("f") | From c0de6a3af2509b16512042d079fe7efafdc7c3da Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 11:15:08 +0100 Subject: [PATCH 149/429] add support for Immutable Record --- .../semmle/javascript/frameworks/Immutable.qll | 15 ++++++++++++++- .../frameworks/Immutable/immutable.js | 9 +++++++-- .../frameworks/Immutable/tests.expected | 2 ++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index 28e05f7f0e2..c6b6441f9d5 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -32,11 +32,15 @@ private module Immutable { /** * An instance of any immutable collection. + * + * This predicate keeps track of which values in the program are Immutable collections. */ API::Node immutableCollection() { - // keep this list in sync with the constructors defined in `storeStep`. + // keep this predicate in sync with the constructors defined in `storeStep`. result = immutableImport().getMember(["Map", "OrderedMap", "List", "fromJS"]).getReturn() or + result = immutableImport().getMember("Record").getReturn().getReturn() + or result = immutableCollection().getMember(["set", "map", "filter", "push"]).getReturn() } @@ -77,6 +81,15 @@ private module Immutable { result = call and prop = DataFlow::PseudoProperties::arrayElement() ) + or + // Immutable.Record({defaults})({values}). + exists(API::CallNode factoryCall, API::CallNode recordCall | + factoryCall = immutableImport().getMember("Record").getACall() and + recordCall = factoryCall.getReturn().getACall() + | + pred = [factoryCall, recordCall].getOptionArgument(0, prop) and + result = recordCall + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index 0b62c174039..38cdc3f2708 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -1,7 +1,7 @@ var obj = { a: source("a"), b: source("b1") }; sink(obj["a"]); // NOT OK -const { Map, fromJS, List, OrderedMap } = require('immutable'); +const { Map, fromJS, List, OrderedMap, Record } = require('immutable'); const map1 = Map(obj); @@ -34,4 +34,9 @@ List(["safe"]).push(source()).forEach(x => sink(x)); // NOT OK const map4 = OrderedMap({}).set("f", source()); -sink(map4.get("f")); // NOT OK \ No newline at end of file +sink(map4.get("f")); // NOT OK + +const map5 = Record({a: source(), b: null, c: null})({b: source()}); +sink(map5.get("a")); // NOT OK +sink(map5.get("b")); // NOT OK +sink(map5.get("c")); // OK \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index de0b333cba9..0686da007f0 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -11,3 +11,5 @@ | immutable.js:31:7:31:14 | source() | immutable.js:31:75:31:75 | x | | immutable.js:33:21:33:28 | source() | immutable.js:33:49:33:49 | x | | immutable.js:36:38:36:45 | source() | immutable.js:37:6:37:18 | map4.get("f") | +| immutable.js:39:25:39:32 | source() | immutable.js:40:6:40:18 | map5.get("a") | +| immutable.js:39:58:39:65 | source() | immutable.js:41:6:41:18 | map5.get("b") | From b74df66463ea5f17918797c42678b30089d6c6c7 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 11:48:30 +0100 Subject: [PATCH 150/429] implement Immutable merge --- .../javascript/frameworks/Immutable.qll | 19 ++++++++++++++++--- .../frameworks/Immutable/immutable.js | 10 ++++++++-- .../frameworks/Immutable/tests.expected | 2 ++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index c6b6441f9d5..a56aab93843 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -36,12 +36,13 @@ private module Immutable { * This predicate keeps track of which values in the program are Immutable collections. */ API::Node immutableCollection() { - // keep this predicate in sync with the constructors defined in `storeStep`. - result = immutableImport().getMember(["Map", "OrderedMap", "List", "fromJS"]).getReturn() + // keep this predicate in sync with the constructors defined in `storeStep`/`step`. + result = + immutableImport().getMember(["Map", "OrderedMap", "List", "fromJS", "merge"]).getReturn() or result = immutableImport().getMember("Record").getReturn().getReturn() or - result = immutableCollection().getMember(["set", "map", "filter", "push"]).getReturn() + result = immutableCollection().getMember(["set", "map", "filter", "push", "merge"]).getReturn() } /** @@ -125,6 +126,18 @@ private module Immutable { pred = call.getReceiver() and result = call ) + or + // Immutable.merge(x, y) + exists(DataFlow::CallNode call | call = immutableImport().getMember("merge").getACall() | + pred = call.getAnArgument() and + result = call + ) + or + // collection.merge(other) + exists(DataFlow::CallNode call | call = immutableCollection().getMember("merge").getACall() | + pred = [call.getAnArgument(), call.getReceiver()] and + result = call + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index 38cdc3f2708..f605d1e917f 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -1,7 +1,7 @@ var obj = { a: source("a"), b: source("b1") }; sink(obj["a"]); // NOT OK -const { Map, fromJS, List, OrderedMap, Record } = require('immutable'); +const { Map, fromJS, List, OrderedMap, Record, merge } = require('immutable'); const map1 = Map(obj); @@ -39,4 +39,10 @@ sink(map4.get("f")); // NOT OK const map5 = Record({a: source(), b: null, c: null})({b: source()}); sink(map5.get("a")); // NOT OK sink(map5.get("b")); // NOT OK -sink(map5.get("c")); // OK \ No newline at end of file +sink(map5.get("c")); // OK + +const map6 = merge(Map({}), Record({a: source()})()); +sink(map6.get("a")); // NOT OK + +const map7 = map6.merge(Map({b: source()})); +sink(map7.get("b")); // NOT OK \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index 0686da007f0..cead857c6b7 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -13,3 +13,5 @@ | immutable.js:36:38:36:45 | source() | immutable.js:37:6:37:18 | map4.get("f") | | immutable.js:39:25:39:32 | source() | immutable.js:40:6:40:18 | map5.get("a") | | immutable.js:39:58:39:65 | source() | immutable.js:41:6:41:18 | map5.get("b") | +| immutable.js:44:40:44:47 | source() | immutable.js:45:6:45:18 | map6.get("a") | +| immutable.js:47:33:47:40 | source() | immutable.js:48:6:48:18 | map7.get("b") | From 6cbf7b3267df70be1f1b167e64269109e3eb16be Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 12:05:04 +0100 Subject: [PATCH 151/429] add `of` `Set`, `Stack` and similar to the Immutable model --- .../javascript/frameworks/Immutable.qll | 25 +++++++++++++++++-- .../frameworks/Immutable/immutable.js | 14 +++++++++-- .../frameworks/Immutable/tests.expected | 5 ++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll index a56aab93843..16cf7de2cc0 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Immutable.qll @@ -38,10 +38,18 @@ private module Immutable { API::Node immutableCollection() { // keep this predicate in sync with the constructors defined in `storeStep`/`step`. result = - immutableImport().getMember(["Map", "OrderedMap", "List", "fromJS", "merge"]).getReturn() + immutableImport() + .getMember(["Map", "OrderedMap", "List", "Stack", "Set", "OrderedSet", "fromJS", "merge"]) + .getReturn() or result = immutableImport().getMember("Record").getReturn().getReturn() or + result = + immutableImport() + .getMember(["List", "Set", "OrderedSet", "Stack"]) + .getMember("of") + .getReturn() + or result = immutableCollection().getMember(["set", "map", "filter", "push", "merge"]).getReturn() } @@ -59,7 +67,7 @@ private module Immutable { or // Immutable.List() exists(DataFlow::CallNode call, DataFlow::ArrayCreationNode arr | - call = immutableImport().getMember("List").getACall() + call = immutableImport().getMember(["List", "Stack", "Set", "OrderedSet"]).getACall() | arr = call.getArgument(0).getALocalSource() and exists(int i | @@ -91,6 +99,19 @@ private module Immutable { pred = [factoryCall, recordCall].getOptionArgument(0, prop) and result = recordCall ) + or + // List/Set/Stack.of(values) + exists(API::CallNode call | + call = + immutableImport() + .getMember(["List", "Set", "OrderedSet", "Stack"]) + .getMember("of") + .getACall() + | + pred = call.getAnArgument() and + result = call and + prop = DataFlow::PseudoProperties::arrayElement() + ) } /** diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js index f605d1e917f..78104b6a20a 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js +++ b/javascript/ql/test/library-tests/frameworks/Immutable/immutable.js @@ -1,7 +1,7 @@ var obj = { a: source("a"), b: source("b1") }; sink(obj["a"]); // NOT OK -const { Map, fromJS, List, OrderedMap, Record, merge } = require('immutable'); +const { Map, fromJS, List, OrderedMap, Record, merge, Stack, Set, OrderedSet } = require('immutable'); const map1 = Map(obj); @@ -45,4 +45,14 @@ const map6 = merge(Map({}), Record({a: source()})()); sink(map6.get("a")); // NOT OK const map7 = map6.merge(Map({b: source()})); -sink(map7.get("b")); // NOT OK \ No newline at end of file +sink(map7.get("b")); // NOT OK + +Stack.of(source(), "foobar").forEach(x => sink(x)); // NOT OK + +List.of(source()).filter(x => true).toList().forEach(x => sink(x)); // NOT OK + +Set.of(source()).filter(x => true).toList().forEach(x => sink(x)); // NOT OK + +Set([source()]).filter(x => true).toList().forEach(x => sink(x)); // NOT OK + +OrderedSet([source()]).filter(x => true).toList().forEach(x => sink(x)); // NOT OK \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected index cead857c6b7..6edc4ee1a96 100644 --- a/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/Immutable/tests.expected @@ -15,3 +15,8 @@ | immutable.js:39:58:39:65 | source() | immutable.js:41:6:41:18 | map5.get("b") | | immutable.js:44:40:44:47 | source() | immutable.js:45:6:45:18 | map6.get("a") | | immutable.js:47:33:47:40 | source() | immutable.js:48:6:48:18 | map7.get("b") | +| immutable.js:50:10:50:17 | source() | immutable.js:50:48:50:48 | x | +| immutable.js:52:9:52:16 | source() | immutable.js:52:64:52:64 | x | +| immutable.js:54:8:54:15 | source() | immutable.js:54:63:54:63 | x | +| immutable.js:56:6:56:13 | source() | immutable.js:56:62:56:62 | x | +| immutable.js:58:13:58:20 | source() | immutable.js:58:69:58:69 | x | From ac0f2d37db0db2942e4a60ffde58cca28cd3fd70 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 12:09:07 +0100 Subject: [PATCH 152/429] Python: Fix small typo in test-output Spotted by yoff in https://github.com/github/codeql/pull/5069#discussion_r570063207 --- python/ql/test/experimental/dataflow/import-helper/test4.py | 2 +- python/ql/test/experimental/dataflow/import-helper/test7.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/test/experimental/dataflow/import-helper/test4.py b/python/ql/test/experimental/dataflow/import-helper/test4.py index 88ed9a69864..9e7f4f66d27 100644 --- a/python/ql/test/experimental/dataflow/import-helper/test4.py +++ b/python/ql/test/experimental/dataflow/import-helper/test4.py @@ -1,4 +1,4 @@ import mypkg.foo as _foo import mypkg.bar as _bar -print(_foo) # Date: Thu, 4 Feb 2021 12:18:07 +0100 Subject: [PATCH 153/429] Python: Fix typos in test files Co-authored-by: yoff --- python/ql/test/experimental/dataflow/ApiGraphs/test7.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test7.py b/python/ql/test/experimental/dataflow/ApiGraphs/test7.py index 6ecb6e3e3f8..e74159efaed 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test7.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test7.py @@ -4,7 +4,7 @@ print(foo) #$ use=moduleImport("mypkg").getMember("foo") // 42 import mypkg.foo #$ use=moduleImport("mypkg") print(foo) #$ use=moduleImport("mypkg").getMember("foo") // 42 -print(mypkg.foo) #$ use=moduleImport("mypkg").getMember("foo") // Date: Thu, 4 Feb 2021 12:41:17 +0100 Subject: [PATCH 154/429] Python: Fix more typos Co-authored-by: Rasmus Wriedt Larsen --- python/ql/test/experimental/dataflow/ApiGraphs/test4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test4.py b/python/ql/test/experimental/dataflow/ApiGraphs/test4.py index 200d3b820c7..c1790aa2263 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test4.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test4.py @@ -1,4 +1,4 @@ import mypkg.foo as _foo #$ use=moduleImport("mypkg").getMember("foo") import mypkg.bar as _bar #$ use=moduleImport("mypkg").getMember("bar") -print(_foo) #$ use=moduleImport("mypkg").getMember("foo") // Date: Thu, 4 Feb 2021 11:45:15 +0000 Subject: [PATCH 155/429] Update CodeQL workflow Bring the CodeQL workflow up to date with the latest recommended configuration, which analyses the merge commit of pull requests (not the head of the PR branch). --- .github/workflows/codeql-analysis.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f1844da86cf..97cd263364c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -14,16 +14,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 From 121ffbbfa8c78ec150fba7d4b203b52bbb065683 Mon Sep 17 00:00:00 2001 From: Julian Tibble Date: Thu, 4 Feb 2021 11:49:15 +0000 Subject: [PATCH 156/429] Restrict triggers for CodeQL workflow Analysing all branches on both 'push' and 'pull request' events causes duplicate analysis. It is only necessary to analyse the _target_ branches of pull requests on push. --- .github/workflows/codeql-analysis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 97cd263364c..7f218e99da4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -2,7 +2,13 @@ name: "Code scanning - action" on: push: + branches: + - main + - 'rc/*' pull_request: + branches: + - main + - 'rc/*' schedule: - cron: '0 9 * * 1' From d01d7eea822a46121283fa123af02e72c8b3a6e0 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 13:08:19 +0100 Subject: [PATCH 157/429] Python: Add documentation from `DataFlowUtil::importNode` --- python/ql/src/semmle/python/ApiGraphs.qll | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 49f1ee1303c..28918f438cb 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -257,7 +257,29 @@ module API { ) } - /** Holds if `imp` is an import of a module named `name` */ + /** + * Holds if `import_node` is an import of a module named `name` + * + * Ignores relative imports (`from ..foo import bar`). + * + * Note that for the statement `import pkg.mod`, the new variable introduced is `pkg` that is a + * reference to the module `pkg`. + * + * This predicate handles (with optional `... as `): + * 1. `import ` + * 2. `from import ` when ` = + "." + ` + * 3. `from import ` when ` = + "." + ` + * + * Finally, in `from import ` we consider the `ImportExpr` corresponding to + * `` to be a reference to that module. + * + * Note: + * While it is technically possible that `import mypkg.foo` and `from mypkg import foo` can give different values, + * it's highly unlikely that this will be a problem in production level code. + * Example: If `mypkg/__init__.py` contains `foo = 42`, then `from mypkg import foo` will not import the module + * `mypkg/foo.py` but the variable `foo` containing `42` -- however, `import mypkg.foo` will always cause `mypkg.foo` + * to refer to the module. + */ private predicate imports(DataFlow::Node import_node, string name) { exists(Variable var, Import imp, Alias alias | alias = imp.getAName() and @@ -271,6 +293,25 @@ module API { import_node.asExpr() = alias.getValue() ) or + // Although it may seem superfluous to consider the `foo` part of `from foo import bar as baz` to + // be a reference to a module (since that reference only makes sense locally within the `import` + // statement), it's important for our use of type trackers to consider this local reference to + // also refer to the `foo` module. That way, if one wants to track references to the `bar` + // attribute using a type tracker, one can simply write + // + // ```ql + // DataFlow::Node bar_attr_tracker(TypeTracker t) { + // t.startInAttr("bar") and + // result = foo_module_tracker() + // or + // exists(TypeTracker t2 | result = bar_attr_tracker(t2).track(t2, t)) + // } + // ``` + // + // Where `foo_module_tracker` is a type tracker that tracks references to the `foo` module. + // Because named imports are modelled as `AttrRead`s, the statement `from foo import bar as baz` + // is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a + // reference to `foo.bar`, as desired. exists(ImportExpr imp_expr | not imp_expr.isRelative() and imp_expr.getName() = name and From b55921a391a4a49bf3155b8d35057ffac49ecdff Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 13:25:02 +0100 Subject: [PATCH 158/429] Update cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- .../CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql index 7b110ec24db..3de8ddefeaf 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -17,7 +17,7 @@ import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import semmle.code.cpp.controlflow.Guards -/** Holds if `sub` will never be nonnegative. */ +/** Holds if `sub` will never be negative. */ predicate nonNegative(SubExpr sub) { not exprMightOverflowNegatively(sub.getFullyConverted()) or From 2131f3580167e37e23daf77313bc4cde0a6b4615 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:41:40 +0300 Subject: [PATCH 159/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.ql --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index 403d8388b17..0181744bb86 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -1,5 +1,5 @@ /** - * @name Сonfusion In Detecting And Handling Memory Allocation Errors + * @name onfusion In Detecting And Handling Memory Allocation Errors * @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. * --the programmer can get confused when check the error that occurs when allocating memory incorrectly. * @kind problem @@ -47,9 +47,7 @@ class WrongCheckErrorOperatorNew extends FunctionCall { * Holds if handler `try ... catch` exists. */ predicate isExistsTryCatchBlock() { - exists(TryStmt ts | - this.getEnclosingStmt() = ts.getStmt().getAChild*() - ) + exists(TryStmt ts | this.getEnclosingStmt() = ts.getStmt().getAChild*()) } /** From a43167faf7cbb82cf0d4f3eaa5ca492818e7a9f0 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:44:28 +0300 Subject: [PATCH 160/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp index c3e543a1b58..9e6cb2d89ce 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.qhelp @@ -3,7 +3,7 @@ "qhelp.dtd"> -

    When using the new operator to allocate memory, you need to pay attention to the different ways of detecting errors. ::operator new(std::size_t) throws an exception on error, whereas ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. The programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    +

    When using the new operator to allocate memory, you need to pay attention to the different ways of detecting errors. ::operator new(std::size_t) throws an exception on error, whereas ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. The programmer can get confused and check the error that occurs when allocating memory incorrectly. That can lead to an unhandled program termination or to a violation of the program logic.

    From 43045c1f034b9fe2eeeb7f6746f02a7392921725 Mon Sep 17 00:00:00 2001 From: ihsinme <61293369+ihsinme@users.noreply.github.com> Date: Thu, 4 Feb 2021 15:47:16 +0300 Subject: [PATCH 161/429] Update WrongInDetectingAndHandlingMemoryAllocationErrors.ql --- .../WrongInDetectingAndHandlingMemoryAllocationErrors.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql index 0181744bb86..dd9c16fac11 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-570/WrongInDetectingAndHandlingMemoryAllocationErrors.ql @@ -1,5 +1,5 @@ /** - * @name onfusion In Detecting And Handling Memory Allocation Errors + * @name Detect And Handle Memory Allocation Errors * @description --::operator new(std::size_t) throws an exception on error, and ::operator new(std::size_t, const std::nothrow_t &) returns zero on error. * --the programmer can get confused when check the error that occurs when allocating memory incorrectly. * @kind problem From 4af7bc8090e41da6c30df62b50694c7cb8f6a63f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 14:30:56 +0100 Subject: [PATCH 162/429] Docs: Use /blob/ instead of /tree/ for direct query link It doesn't have a huge impact, since there is a working redirect in place, but still more correct to use /blob/ :) For example, https://github.com/github/codeql/tree/main/python/ql/src/Security/CWE-094/CodeInjection.ql redirects to https://github.com/github/codeql/blob/main/python/ql/src/Security/CWE-094/CodeInjection.ql --- docs/codeql/query-help-markdown.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/codeql/query-help-markdown.py b/docs/codeql/query-help-markdown.py index 9313d4b170d..350c9aefce2 100644 --- a/docs/codeql/query-help-markdown.py +++ b/docs/codeql/query-help-markdown.py @@ -188,10 +188,10 @@ for lang in languages: # Build a link to the query source file for display in the query help if "go" in prefix_repo_nwo(queryfile): transform_link = prefix_repo_nwo(queryfile).replace( - "codeql-go", "codeql-go/tree/main").replace(" ", "%20").replace("\\", "/") + "codeql-go", "codeql-go/blob/main").replace(" ", "%20").replace("\\", "/") else: transform_link = prefix_repo_nwo(queryfile).replace( - "codeql", "codeql/tree/main").replace(" ", "%20").replace("\\", "/") + "codeql", "codeql/blob/main").replace(" ", "%20").replace("\\", "/") query_link = "[Click to see the query in the CodeQL repository](https://github.com/" + \ transform_link + ")\n" From ce27831b767c4050f150660ad6f050d362800284 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 4 Feb 2021 14:43:51 +0100 Subject: [PATCH 163/429] C#: Fix nullable warnings and some code quality issues --- .../Semmle.Extraction.CIL/Entities/ConstructedType.cs | 1 - .../Semmle.Extraction.CIL/Entities/Instruction.cs | 2 +- .../Entities/NamedTypeIdWriter.cs | 1 - .../NoMetadataHandleType.FullyQualifiedNameParser.cs | 2 +- .../Entities/NoMetadataHandleType.cs | 2 +- .../Entities/SignatureDecoder.cs | 1 - .../Entities/TypeDefinitionType.cs | 4 +--- .../Entities/TypeReferenceType.cs | 2 -- .../Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs | 2 +- csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs | 1 - .../Semmle.Extraction.CIL/PDB/NativePdbReader.cs | 1 - .../extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs | 5 ++--- .../Semmle.Extraction.CSharp.Driver/Driver.cs | 2 +- .../Semmle.Extraction.CSharp/Entities/CommentLine.cs | 4 +--- .../Entities/LocalFunction.cs | 2 -- .../Populators/DirectiveVisitor.cs | 1 - .../extractor/Semmle.Extraction/CommentProcessing.cs | 11 +++++++---- csharp/extractor/Semmle.Extraction/Context.cs | 10 +++++----- .../extractor/Semmle.Extraction/Entities/Assembly.cs | 2 +- .../Semmle.Extraction/Entities/ExtractionError.cs | 3 ++- .../Semmle.Extraction/Entities/SourceLocation.cs | 6 ++---- csharp/extractor/Semmle.Extraction/Extractor.cs | 1 - csharp/extractor/Semmle.Extraction/Message.cs | 10 +++++----- csharp/extractor/Semmle.Util/Win32.cs | 2 +- 24 files changed, 32 insertions(+), 46 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs index 5be671055eb..be2ab5da4d8 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ConstructedType.cs @@ -1,5 +1,4 @@ using System; -using Microsoft.CodeAnalysis; using System.Linq; using System.Collections.Generic; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 9512cfc5690..75d0aab454a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -481,7 +481,7 @@ namespace Semmle.Extraction.CIL.Entities // TODO: Find a solution to this. // For now, just log the error - Cx.Cx.ExtractionError("A CIL instruction jumps outside the current method", "", Extraction.Entities.GeneratedLocation.Create(Cx.Cx), "", Util.Logging.Severity.Warning); + Cx.Cx.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Cx.Cx), "", Util.Logging.Severity.Warning); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs index 35881b67257..98f9e94ec82 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NamedTypeIdWriter.cs @@ -1,4 +1,3 @@ -using Microsoft.CodeAnalysis; using System.Linq; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs index d7940be6cc5..999259e9ad6 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.FullyQualifiedNameParser.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CIL.Entities private class FullyQualifiedNameParser { public string ShortName { get; internal set; } - public string? AssemblyName { get; internal set; } + public string? AssemblyName { get; private set; } public IEnumerable? TypeArguments { get; internal set; } public string? UnboundGenericTypeName { get; internal set; } public string ContainerName { get; internal set; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs index fde969d12b9..c1259534f79 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/NoMetadataHandleType.cs @@ -66,7 +66,7 @@ namespace Semmle.Extraction.CIL.Entities private void Populate() { - if (isContainerNamespace) + if (ContainingNamespace is object) { Cx.Populate(ContainingNamespace); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs index a80f456df72..a955ef685c0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs @@ -1,7 +1,6 @@ using System.Reflection.Metadata; using System.Collections.Immutable; using System.IO; -using System.Linq; namespace Semmle.Extraction.CIL.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs index 44bb9020813..461141ae719 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeDefinitionType.cs @@ -1,12 +1,10 @@ using System; -using Microsoft.CodeAnalysis; -using System.Reflection.Metadata; -using System.Collections.Immutable; using System.Linq; using System.Collections.Generic; using System.Reflection; using System.IO; using System.Reflection.Metadata.Ecma335; +using System.Reflection.Metadata; namespace Semmle.Extraction.CIL.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs index 2ffa9e9e5d8..49a15965dd0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeReferenceType.cs @@ -1,7 +1,5 @@ using System; -using Microsoft.CodeAnalysis; using System.Reflection.Metadata; -using System.Collections.Immutable; using System.Linq; using System.Collections.Generic; using System.IO; diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs index c6d02a119dc..81c91946657 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs @@ -76,7 +76,7 @@ namespace Semmle.Extraction.PDB out provider, out _)) { - return new MetadataPdbReader(provider); + return new MetadataPdbReader(provider!); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs index e0d41bed77a..6a534a4dd20 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/Method.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Reflection.Metadata; using System.Linq; namespace Semmle.Extraction.PDB diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs index 6d49dd8fd85..0a8479fb454 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs @@ -6,7 +6,6 @@ using Microsoft.DiaSymReader; using System.Reflection.Metadata.Ecma335; using System.Reflection.Metadata; using System.IO; -using System.Reflection; namespace Semmle.Extraction.PDB { diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs index c84cd6a824f..1f0f1b455dc 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs @@ -1,9 +1,8 @@ -using System.Linq; -using System.Reflection.PortableExecutable; +using System.Reflection.PortableExecutable; namespace Semmle.Extraction.PDB { - internal class PdbReader + internal static class PdbReader { /// /// Returns the PDB information associated with an assembly. diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs index 5806bd375b1..1c4142097fe 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Driver.cs @@ -3,7 +3,7 @@ namespace Semmle.Extraction.CSharp /// /// A command-line driver for the extractor. /// - public class Driver + public static class Driver { public static int Main(string[] args) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs index f6348211695..e390cb8c509 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs @@ -1,6 +1,4 @@ using Semmle.Extraction.CommentProcessing; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Semmle.Extraction.Entities; using System.IO; @@ -21,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities public string Text { get { return symbol.Item2; } } public string RawText { get; private set; } - private Extraction.Entities.Location location; + private Location location; public override void Populate(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs index 921036250d1..b376566e841 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/LocalFunction.cs @@ -1,8 +1,6 @@ using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using System; using System.IO; -using System.Linq; namespace Semmle.Extraction.CSharp.Entities { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index 4098576a86d..9ec8d095290 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs index f407f5703fe..201ac705136 100644 --- a/csharp/extractor/Semmle.Extraction/CommentProcessing.cs +++ b/csharp/extractor/Semmle.Extraction/CommentProcessing.cs @@ -53,7 +53,7 @@ namespace Semmle.Extraction.CommentProcessing if (l2 == null) return 1; - var diff = l1.SourceTree == l2.SourceTree ? 0 : l1.SourceTree.FilePath.CompareTo(l2.SourceTree.FilePath); + var diff = l1.SourceTree == l2.SourceTree ? 0 : l1.SourceTree!.FilePath.CompareTo(l2.SourceTree!.FilePath); if (diff != 0) return diff; diff = l1.SourceSpan.Start - l2.SourceSpan.Start; @@ -384,9 +384,12 @@ namespace Semmle.Extraction.CommentProcessing /// The line to add. public void AddCommentLine(ICommentLine line) { - Location = !lines.Any() ? - line.Location : - Location.Create(line.Location.SourceTree, new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start)); + Location = !lines.Any() + ? line.Location + : Location.Create( + line.Location.SourceTree!, + new TextSpan(Location.SourceSpan.Start, line.Location.SourceSpan.End - Location.SourceSpan.Start)); + lines.Add(line); } } diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 10a24990a13..e6b4826f2ef 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -215,7 +215,7 @@ namespace Semmle.Extraction } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { - ExtractionError("Uncaught exception", ex.Message, Entities.Location.Create(this), ex.StackTrace); + ExtractionError($"Uncaught exception. {ex.Message}", null, Entities.Location.Create(this), ex.StackTrace); } } } @@ -246,7 +246,7 @@ namespace Semmle.Extraction public ICommentGenerator CommentGenerator { get; } = new CommentProcessor(); - private IExtractionScope scope; + private readonly IExtractionScope scope; public bool IsAssemblyScope => scope is AssemblyScope; @@ -423,7 +423,7 @@ namespace Semmle.Extraction /// The location of the error. /// An optional stack trace of the error, or null. /// The severity of the error. - public void ExtractionError(string message, string entityText, Entities.Location location, string? stackTrace = null, Severity severity = Severity.Error) + public void ExtractionError(string message, string? entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) { var msg = new Message(message, entityText, location, stackTrace, severity); ExtractionError(msg); @@ -447,7 +447,7 @@ namespace Semmle.Extraction } else { - ExtractionError(message, "", Entities.Location.Create(this)); + ExtractionError(message, null, Entities.Location.Create(this)); } } @@ -531,7 +531,7 @@ namespace Semmle.Extraction } else { - message = new Message("Uncaught exception", ex.Message, Entities.Location.Create(context), ex.StackTrace); + message = new Message($"Uncaught exception. {ex.Message}", null, Entities.Location.Create(context), ex.StackTrace); } context.ExtractionError(message); diff --git a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs index a6210356199..df3a5757618 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.Entities } else { - assembly = init.MetadataModule.ContainingAssembly; + assembly = init.MetadataModule!.ContainingAssembly; var identity = assembly.Identity; var idString = identity.Name + " " + identity.Version; assemblyPath = cx.Extractor.GetAssemblyFile(idString); diff --git a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs index 82257513260..3df0ce3bb61 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs @@ -14,7 +14,8 @@ namespace Semmle.Extraction.Entities protected override void Populate(TextWriter trapFile) { - trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText, msg.Location ?? Location.Create(cx), msg.StackTrace); + trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText ?? string.Empty, + msg.Location ?? Location.Create(cx), msg.StackTrace ?? string.Empty); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs index 41688033f04..e7bc4e3ea44 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs @@ -15,11 +15,9 @@ namespace Semmle.Extraction.Entities public class NonGeneratedSourceLocation : SourceLocation { - protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location? init) + protected NonGeneratedSourceLocation(Context cx, Microsoft.CodeAnalysis.Location init) : base(cx, init) { - if (init is null) - throw new ArgumentException("Location may not be null", nameof(init)); Position = init.GetLineSpan(); FileEntity = File.Create(Context, Position.Path); } @@ -32,7 +30,7 @@ namespace Semmle.Extraction.Entities Position.Span.Start.Line + 1, Position.Span.Start.Character + 1, Position.Span.End.Line + 1, Position.Span.End.Character); - var mapped = symbol.GetMappedLineSpan(); + var mapped = symbol!.GetMappedLineSpan(); if (mapped.HasMappedPath && mapped.IsValid) { var mappedLoc = Create(Context, Microsoft.CodeAnalysis.Location.Create(mapped.Path, default, mapped.Span)); diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index 1931aeeeb33..4f5c27f3a90 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using Microsoft.CodeAnalysis; using Semmle.Util.Logging; diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction/Message.cs index fbe91fb95e6..0a2a62e13a2 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction/Message.cs @@ -13,22 +13,22 @@ namespace Semmle.Extraction { public Severity Severity { get; } public string Text { get; } - public string StackTrace { get; } - public string EntityText { get; } + public string? StackTrace { get; } + public string? EntityText { get; } public Entities.Location? Location { get; } - public Message(string text, string entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) + public Message(string text, string? entityText, Entities.Location? location, string? stackTrace = null, Severity severity = Severity.Error) { Severity = severity; Text = text; - StackTrace = stackTrace ?? ""; + StackTrace = stackTrace; EntityText = entityText; Location = location; } public static Message Create(Context cx, string text, ISymbol symbol, string? stackTrace = null, Severity severity = Severity.Error) { - return new Message(text, symbol.ToString() ?? "", Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); + return new Message(text, symbol.ToString(), Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); } public static Message Create(Context cx, string text, SyntaxNode node, string? stackTrace = null, Severity severity = Severity.Error) diff --git a/csharp/extractor/Semmle.Util/Win32.cs b/csharp/extractor/Semmle.Util/Win32.cs index fe198b9612a..046a0957e87 100644 --- a/csharp/extractor/Semmle.Util/Win32.cs +++ b/csharp/extractor/Semmle.Util/Win32.cs @@ -8,7 +8,7 @@ namespace Semmle.Util /// /// Holder for various Win32 functions. /// - public class Win32 + public static class Win32 { [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern int GetFinalPathNameByHandle( // lgtm[cs/unmanaged-code] From 5927ce5d69bd4df26e2774a5fb476ff575b95be5 Mon Sep 17 00:00:00 2001 From: Sauyon Lee Date: Thu, 4 Feb 2021 14:35:43 +0000 Subject: [PATCH 164/429] Add GoKit to Go supported library list --- docs/codeql/support/reusables/frameworks.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 4427407fe9d..867c0cce036 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -33,6 +33,7 @@ Go built-in support glog, Logging library go-restful, Web application framework go-sh, Utility library + GoKit, Microservice toolkit Gokogiri, XPath library golang.org/x/crypto/ssh, Network communicator golang.org/x/net/websocket, Network communicator From 3fe715abb6e85538e43246eb1722d3558eee4a02 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 15:49:37 +0100 Subject: [PATCH 165/429] Python: Fix query names that inclde __ (dunder) Without backticks, the text UNDERSCORE UNDERSCORE eq UNDERSCORE UNDERSCORE would be considered to make things bold in our markdown output, making the query info look strange. Example https://codeql.github.com/codeql-query-help/python/py-slots-in-old-style-class/ --- python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql | 2 +- python/ql/src/Classes/InitCallsSubclassMethod.ql | 4 ++-- python/ql/src/Classes/MaybeUndefinedClassAttribute.ql | 2 +- python/ql/src/Classes/MissingCallToDel.ql | 4 ++-- python/ql/src/Classes/MissingCallToInit.ql | 4 ++-- python/ql/src/Classes/MutatingDescriptor.ql | 2 +- python/ql/src/Classes/OverwritingAttributeInSuperClass.ql | 2 +- python/ql/src/Classes/SlotsInOldStyleClass.ql | 4 ++-- python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql | 4 ++-- python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql | 4 ++-- python/ql/src/Classes/UndefinedClassAttribute.ql | 2 +- python/ql/src/Classes/UselessClass.ql | 2 +- .../src/Classes/WrongNumberArgumentsInClassInstantiation.ql | 2 +- python/ql/src/Expressions/ExplicitCallToDel.ql | 4 ++-- python/ql/src/Expressions/IncorrectComparisonUsingIs.ql | 2 +- python/ql/src/Expressions/NonPortableComparisonUsingIs.ql | 2 +- python/ql/src/Functions/ExplicitReturnInInit.ql | 4 ++-- python/ql/src/Functions/InitIsGenerator.ql | 4 ++-- python/ql/src/Functions/IterReturnsNonIterator.ql | 4 ++-- python/ql/src/Functions/IterReturnsNonSelf.ql | 4 ++-- python/ql/src/Functions/OverlyComplexDelMethod.ql | 4 ++-- python/ql/src/Imports/UnintentionalImport.ql | 2 +- python/ql/src/Statements/TopLevelPrint.ql | 2 +- python/ql/src/Variables/UndefinedExport.ql | 2 +- 24 files changed, 36 insertions(+), 36 deletions(-) diff --git a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql index 15d44f9a1eb..68542bbc243 100644 --- a/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql +++ b/python/ql/src/Classes/DefineEqualsWhenAddingAttributes.ql @@ -1,5 +1,5 @@ /** - * @name __eq__ not overridden when adding attributes + * @name `__eq__` not overridden when adding attributes * @description When adding new attributes to instances of a class, equality for that class needs to be defined. * @kind problem * @tags reliability diff --git a/python/ql/src/Classes/InitCallsSubclassMethod.ql b/python/ql/src/Classes/InitCallsSubclassMethod.ql index 19865751c53..2fb6e90dd7d 100644 --- a/python/ql/src/Classes/InitCallsSubclassMethod.ql +++ b/python/ql/src/Classes/InitCallsSubclassMethod.ql @@ -1,6 +1,6 @@ /** - * @name __init__ method calls overridden method - * @description Calling a method from __init__ that is overridden by a subclass may result in a partially + * @name `__init__` method calls overridden method + * @description Calling a method from `__init__` that is overridden by a subclass may result in a partially * initialized instance being observed. * @kind problem * @tags reliability diff --git a/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql b/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql index 7f4e27801c2..70934185831 100644 --- a/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql +++ b/python/ql/src/Classes/MaybeUndefinedClassAttribute.ql @@ -1,6 +1,6 @@ /** * @name Maybe undefined class attribute - * @description Accessing an attribute of 'self' that is not initialized in the __init__ method may cause an AttributeError at runtime + * @description Accessing an attribute of `self` that is not initialized in the `__init__` method may cause an AttributeError at runtime * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Classes/MissingCallToDel.ql b/python/ql/src/Classes/MissingCallToDel.ql index e658dba1389..641968789d6 100644 --- a/python/ql/src/Classes/MissingCallToDel.ql +++ b/python/ql/src/Classes/MissingCallToDel.ql @@ -1,6 +1,6 @@ /** - * @name Missing call to __del__ during object destruction - * @description An omitted call to a super-class __del__ method may lead to class instances not being cleaned up properly. + * @name Missing call to `__del__` during object destruction + * @description An omitted call to a super-class `__del__` method may lead to class instances not being cleaned up properly. * @kind problem * @tags efficiency * correctness diff --git a/python/ql/src/Classes/MissingCallToInit.ql b/python/ql/src/Classes/MissingCallToInit.ql index 6daa06de79c..81d1916056e 100644 --- a/python/ql/src/Classes/MissingCallToInit.ql +++ b/python/ql/src/Classes/MissingCallToInit.ql @@ -1,6 +1,6 @@ /** - * @name Missing call to __init__ during object initialization - * @description An omitted call to a super-class __init__ method may lead to objects of this class not being fully initialized. + * @name Missing call to `__init__` during object initialization + * @description An omitted call to a super-class `__init__` method may lead to objects of this class not being fully initialized. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Classes/MutatingDescriptor.ql b/python/ql/src/Classes/MutatingDescriptor.ql index a7118883951..477ecc18206 100644 --- a/python/ql/src/Classes/MutatingDescriptor.ql +++ b/python/ql/src/Classes/MutatingDescriptor.ql @@ -1,5 +1,5 @@ /** - * @name Mutation of descriptor in __get__ or __set__ method. + * @name Mutation of descriptor in `__get__` or `__set__` method. * @description Descriptor objects can be shared across many instances. Mutating them can cause strange side effects or race conditions. * @kind problem * @tags reliability diff --git a/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql b/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql index e77d5ec481f..24887221141 100644 --- a/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql +++ b/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql @@ -1,6 +1,6 @@ /** * @name Overwriting attribute in super-class or sub-class - * @description Assignment to self attribute overwrites attribute previously defined in subclass or superclass __init__ method. + * @description Assignment to self attribute overwrites attribute previously defined in subclass or superclass `__init__` method. * @kind problem * @tags reliability * maintainability diff --git a/python/ql/src/Classes/SlotsInOldStyleClass.ql b/python/ql/src/Classes/SlotsInOldStyleClass.ql index 78b9bd18f29..cd4f9dd5f1d 100644 --- a/python/ql/src/Classes/SlotsInOldStyleClass.ql +++ b/python/ql/src/Classes/SlotsInOldStyleClass.ql @@ -1,6 +1,6 @@ /** - * @name '__slots__' in old-style class - * @description Overriding the class dictionary by declaring '__slots__' is not supported by old-style + * @name `__slots__` in old-style class + * @description Overriding the class dictionary by declaring `__slots__` is not supported by old-style * classes. * @kind problem * @problem.severity error diff --git a/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql b/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql index f1ef04bb89a..da301b6422a 100644 --- a/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql +++ b/python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql @@ -1,6 +1,6 @@ /** - * @name Multiple calls to __del__ during object destruction - * @description A duplicated call to a super-class __del__ method may lead to class instances not be cleaned up properly. + * @name Multiple calls to `__del__` during object destruction + * @description A duplicated call to a super-class `__del__` method may lead to class instances not be cleaned up properly. * @kind problem * @tags efficiency * correctness diff --git a/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql b/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql index cb90cb32510..ec94202c0f3 100644 --- a/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql +++ b/python/ql/src/Classes/SuperclassInitCalledMultipleTimes.ql @@ -1,6 +1,6 @@ /** - * @name Multiple calls to __init__ during object initialization - * @description A duplicated call to a super-class __init__ method may lead to objects of this class not being properly initialized. + * @name Multiple calls to `__init__` during object initialization + * @description A duplicated call to a super-class `__init__` method may lead to objects of this class not being properly initialized. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Classes/UndefinedClassAttribute.ql b/python/ql/src/Classes/UndefinedClassAttribute.ql index 348daa7f9fb..ad66ecd1316 100644 --- a/python/ql/src/Classes/UndefinedClassAttribute.ql +++ b/python/ql/src/Classes/UndefinedClassAttribute.ql @@ -1,6 +1,6 @@ /** * @name Undefined class attribute - * @description Accessing an attribute of 'self' that is not initialized anywhere in the class in the __init__ method may cause an AttributeError at runtime + * @description Accessing an attribute of `self` that is not initialized anywhere in the class in the `__init__` method may cause an AttributeError at runtime * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Classes/UselessClass.ql b/python/ql/src/Classes/UselessClass.ql index 24bf446fc6a..2695e9a7a1d 100644 --- a/python/ql/src/Classes/UselessClass.ql +++ b/python/ql/src/Classes/UselessClass.ql @@ -1,6 +1,6 @@ /** * @name Useless class - * @description Class only defines one public method (apart from __init__ or __new__) and should be replaced by a function + * @description Class only defines one public method (apart from `__init__` or `__new__`) and should be replaced by a function * @kind problem * @tags maintainability * useless-code diff --git a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql index 7afd344eacb..8b456c91dce 100644 --- a/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql +++ b/python/ql/src/Classes/WrongNumberArgumentsInClassInstantiation.ql @@ -1,6 +1,6 @@ /** * @name Wrong number of arguments in a class instantiation - * @description Using too many or too few arguments in a call to the __init__ + * @description Using too many or too few arguments in a call to the `__init__` * method of a class will result in a TypeError at runtime. * @kind problem * @tags reliability diff --git a/python/ql/src/Expressions/ExplicitCallToDel.ql b/python/ql/src/Expressions/ExplicitCallToDel.ql index cb441ce0267..f60945ba05c 100644 --- a/python/ql/src/Expressions/ExplicitCallToDel.ql +++ b/python/ql/src/Expressions/ExplicitCallToDel.ql @@ -1,6 +1,6 @@ /** - * @name __del__ is called explicitly - * @description The __del__ special method is called by the virtual machine when an object is being finalized. It should not be called explicitly. + * @name `__del__` is called explicitly + * @description The `__del__` special method is called by the virtual machine when an object is being finalized. It should not be called explicitly. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql index ab45d6c15d9..5352dc9c9fa 100644 --- a/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql +++ b/python/ql/src/Expressions/IncorrectComparisonUsingIs.ql @@ -1,5 +1,5 @@ /** - * @name Comparison using is when operands support __eq__ + * @name Comparison using is when operands support `__eq__` * @description Comparison using 'is' when equivalence is not the same as identity * @kind problem * @tags reliability diff --git a/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql b/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql index db266020aeb..d9a0f701635 100644 --- a/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql +++ b/python/ql/src/Expressions/NonPortableComparisonUsingIs.ql @@ -1,5 +1,5 @@ /** - * @name Non-portable comparison using is when operands support __eq__ + * @name Non-portable comparison using is when operands support `__eq__` * @description Comparison using 'is' when equivalence is not the same as identity and may not be portable. * @kind problem * @tags portability diff --git a/python/ql/src/Functions/ExplicitReturnInInit.ql b/python/ql/src/Functions/ExplicitReturnInInit.ql index 0ce20249119..000c671396e 100644 --- a/python/ql/src/Functions/ExplicitReturnInInit.ql +++ b/python/ql/src/Functions/ExplicitReturnInInit.ql @@ -1,6 +1,6 @@ /** - * @name __init__ method returns a value - * @description Explicitly returning a value from an __init__ method will raise a TypeError. + * @name `__init__` method returns a value + * @description Explicitly returning a value from an `__init__` method will raise a TypeError. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Functions/InitIsGenerator.ql b/python/ql/src/Functions/InitIsGenerator.ql index 5e3f1ff574b..84bb935ad2e 100644 --- a/python/ql/src/Functions/InitIsGenerator.ql +++ b/python/ql/src/Functions/InitIsGenerator.ql @@ -1,6 +1,6 @@ /** - * @name __init__ method is a generator - * @description __init__ method is a generator. + * @name `__init__` method is a generator + * @description `__init__` method is a generator. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Functions/IterReturnsNonIterator.ql b/python/ql/src/Functions/IterReturnsNonIterator.ql index aba772c9ab7..ed4a240ec4d 100644 --- a/python/ql/src/Functions/IterReturnsNonIterator.ql +++ b/python/ql/src/Functions/IterReturnsNonIterator.ql @@ -1,6 +1,6 @@ /** - * @name __iter__ method returns a non-iterator - * @description The '__iter__' method returns a non-iterator which, if used in a 'for' loop, would raise a 'TypeError'. + * @name `__iter__` method returns a non-iterator + * @description The `__iter__` method returns a non-iterator which, if used in a 'for' loop, would raise a 'TypeError'. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Functions/IterReturnsNonSelf.ql b/python/ql/src/Functions/IterReturnsNonSelf.ql index 3d6c8c7da35..385677a5763 100644 --- a/python/ql/src/Functions/IterReturnsNonSelf.ql +++ b/python/ql/src/Functions/IterReturnsNonSelf.ql @@ -1,6 +1,6 @@ /** - * @name Iterator does not return self from __iter__ method - * @description Iterator does not return self from __iter__ method, violating the iterator protocol. + * @name Iterator does not return self from `__iter__` method + * @description Iterator does not return self from `__iter__` method, violating the iterator protocol. * @kind problem * @tags reliability * correctness diff --git a/python/ql/src/Functions/OverlyComplexDelMethod.ql b/python/ql/src/Functions/OverlyComplexDelMethod.ql index 2fc8789da34..19262332990 100644 --- a/python/ql/src/Functions/OverlyComplexDelMethod.ql +++ b/python/ql/src/Functions/OverlyComplexDelMethod.ql @@ -1,6 +1,6 @@ /** - * @name Overly complex __del__ method - * @description __del__ methods may be called at arbitrary times, perhaps never called at all, and should be simple. + * @name Overly complex `__del__` method + * @description `__del__` methods may be called at arbitrary times, perhaps never called at all, and should be simple. * @kind problem * @tags efficiency * maintainability diff --git a/python/ql/src/Imports/UnintentionalImport.ql b/python/ql/src/Imports/UnintentionalImport.ql index 2a3c2b6460b..cdbcec278dd 100644 --- a/python/ql/src/Imports/UnintentionalImport.ql +++ b/python/ql/src/Imports/UnintentionalImport.ql @@ -1,7 +1,7 @@ /** * @name 'import *' may pollute namespace * @description Importing a module using 'import *' may unintentionally pollute the global - * namespace if the module does not define '__all__' + * namespace if the module does not define `__all__` * @kind problem * @tags maintainability * modularity diff --git a/python/ql/src/Statements/TopLevelPrint.ql b/python/ql/src/Statements/TopLevelPrint.ql index b2d111cce1f..8d35c7c942b 100644 --- a/python/ql/src/Statements/TopLevelPrint.ql +++ b/python/ql/src/Statements/TopLevelPrint.ql @@ -1,6 +1,6 @@ /** * @name Use of a print statement at module level - * @description Using a print statement at module scope (except when guarded by if __name__ == '__main__') will cause surprising output when the module is imported. + * @description Using a print statement at module scope (except when guarded by `if __name__ == '__main__'`) will cause surprising output when the module is imported. * @kind problem * @tags reliability * maintainability diff --git a/python/ql/src/Variables/UndefinedExport.ql b/python/ql/src/Variables/UndefinedExport.ql index 52d51ce4f72..c53e920d477 100644 --- a/python/ql/src/Variables/UndefinedExport.ql +++ b/python/ql/src/Variables/UndefinedExport.ql @@ -1,6 +1,6 @@ /** * @name Explicit export is not defined - * @description Including an undefined attribute in __all__ causes an exception when + * @description Including an undefined attribute in `__all__` causes an exception when * the module is imported using '*' * @kind problem * @tags reliability From 32be53bf72a66f295c08eb02a97ae14429057b61 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 15:53:04 +0100 Subject: [PATCH 166/429] Python: Fix missing in qhelp file --- python/ql/src/Classes/SlotsInOldStyleClass.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp index eb7208d6257..a8d89400622 100644 --- a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp +++ b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp @@ -6,7 +6,7 @@

    The ability to override the class dictionary using a __slots__ declaration is supported only by new-style classes. When you add a __slots__ declaration to an -old-style class it just creates a class attribute called '__slots__'.

    +old-style class it just creates a class attribute called __slots__.

    @@ -17,9 +17,9 @@ You can convert an old-style class to a new-style class by inheriting from

    In the following example the KeyedRef class is an old-style class (no inheritance). The -__slots__ declaration in this class creates a class attribute called '__slots__', the class dictionary is unaffected. The KeyedRef2 class is a new-style class so the __slots__ declaration causes special compact attributes to be created for each name in +__slots__ declaration in this class creates a class attribute called __slots__, the class the slots list and saves space by not creating attribute dictionaries.

    From dcb185b659b7871982de41ed9f5872d2fe3065d8 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 15:53:23 +0100 Subject: [PATCH 167/429] Python: Fix trailing whitespace in a single qhelp file Since I edited already, why not get this little bonus? :D --- python/ql/src/Classes/SlotsInOldStyleClass.qhelp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp index a8d89400622..8d861f4c4a2 100644 --- a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp +++ b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp @@ -5,21 +5,21 @@

    The ability to override the class dictionary using a __slots__ declaration -is supported only by new-style classes. When you add a __slots__ declaration to an +is supported only by new-style classes. When you add a __slots__ declaration to an old-style class it just creates a class attribute called __slots__.

    -

    If you want to override the dictionary for a class, then ensure that the class is a new-style class. +

    If you want to override the dictionary for a class, then ensure that the class is a new-style class. You can convert an old-style class to a new-style class by inheriting from object.

    -

    In the following example the KeyedRef class is an old-style class (no inheritance). The -dictionary is unaffected. The KeyedRef2 class is a new-style class so the -__slots__ declaration causes special compact attributes to be created for each name in +

    In the following example the KeyedRef class is an old-style class (no inheritance). The __slots__ declaration in this class creates a class attribute called __slots__, the class +dictionary is unaffected. The KeyedRef2 class is a new-style class so the +__slots__ declaration causes special compact attributes to be created for each name in the slots list and saves space by not creating attribute dictionaries.

    @@ -28,7 +28,7 @@ the slots list and saves space by not creating attribute dictionaries.

  • Python Glossary: New-style class.
  • -
  • Python Language Reference: New-style and classic +
  • Python Language Reference: New-style and classic classes, __slots__.
  • From 23d9e2646a27ffcfdca3ac1cac7eb62337ae8ae2 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 15:54:10 +0100 Subject: [PATCH 168/429] Python: Fix name of class in example of __slots__ qhelp --- python/ql/src/Classes/SlotsInOldStyleClass.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp index 8d861f4c4a2..9ee18f8dd80 100644 --- a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp +++ b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp @@ -16,9 +16,9 @@ You can convert an old-style class to a new-style class by inheriting from -

    In the following example the KeyedRef class is an old-style class (no inheritance). The +

    In the following example the Point class is an old-style class (no inheritance). The __slots__ declaration in this class creates a class attribute called __slots__, the class -dictionary is unaffected. The KeyedRef2 class is a new-style class so the +dictionary is unaffected. The Point2 class is a new-style class so the __slots__ declaration causes special compact attributes to be created for each name in the slots list and saves space by not creating attribute dictionaries.

    From b94658fd52b3dfd3b0157d878c37b9addd8e44c6 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 4 Feb 2021 15:54:37 +0100 Subject: [PATCH 169/429] Python: Highlight that __slots__ query is only for Python 2 in qhelp Since I was already editing this file, it was easy to just add this extra bit of info. --- python/ql/src/Classes/SlotsInOldStyleClass.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp index 9ee18f8dd80..27474b847e3 100644 --- a/python/ql/src/Classes/SlotsInOldStyleClass.qhelp +++ b/python/ql/src/Classes/SlotsInOldStyleClass.qhelp @@ -16,7 +16,7 @@ You can convert an old-style class to a new-style class by inheriting from -

    In the following example the Point class is an old-style class (no inheritance). The +

    In the following Python 2 example the Point class is an old-style class (no inheritance). The __slots__ declaration in this class creates a class attribute called __slots__, the class dictionary is unaffected. The Point2 class is a new-style class so the __slots__ declaration causes special compact attributes to be created for each name in From e54c925b70e28f2d24486103f996c7e5981d2411 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 15:58:15 +0100 Subject: [PATCH 170/429] Python: Greatly simplify `imports/2` predicate --- python/ql/src/semmle/python/ApiGraphs.qll | 67 +++-------------------- 1 file changed, 8 insertions(+), 59 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 28918f438cb..dc658dcc2be 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -258,67 +258,16 @@ module API { } /** - * Holds if `import_node` is an import of a module named `name` + * Holds if `imp` is a data-flow node inside an import statement that refers to a module by the + * name `name`. * - * Ignores relative imports (`from ..foo import bar`). - * - * Note that for the statement `import pkg.mod`, the new variable introduced is `pkg` that is a - * reference to the module `pkg`. - * - * This predicate handles (with optional `... as `): - * 1. `import ` - * 2. `from import ` when ` = + "." + ` - * 3. `from import ` when ` = + "." + ` - * - * Finally, in `from import ` we consider the `ImportExpr` corresponding to - * `` to be a reference to that module. - * - * Note: - * While it is technically possible that `import mypkg.foo` and `from mypkg import foo` can give different values, - * it's highly unlikely that this will be a problem in production level code. - * Example: If `mypkg/__init__.py` contains `foo = 42`, then `from mypkg import foo` will not import the module - * `mypkg/foo.py` but the variable `foo` containing `42` -- however, `import mypkg.foo` will always cause `mypkg.foo` - * to refer to the module. + * Ignores relative imports, such as `from ..foo.bar import baz`. */ - private predicate imports(DataFlow::Node import_node, string name) { - exists(Variable var, Import imp, Alias alias | - alias = imp.getAName() and - alias.getAsname() = var.getAStore() and - ( - name = alias.getValue().(ImportMember).getImportedModuleName() - or - name = alias.getValue().(ImportExpr).getImportedModuleName() and - not alias.getValue().(ImportExpr).isRelative() - ) and - import_node.asExpr() = alias.getValue() - ) - or - // Although it may seem superfluous to consider the `foo` part of `from foo import bar as baz` to - // be a reference to a module (since that reference only makes sense locally within the `import` - // statement), it's important for our use of type trackers to consider this local reference to - // also refer to the `foo` module. That way, if one wants to track references to the `bar` - // attribute using a type tracker, one can simply write - // - // ```ql - // DataFlow::Node bar_attr_tracker(TypeTracker t) { - // t.startInAttr("bar") and - // result = foo_module_tracker() - // or - // exists(TypeTracker t2 | result = bar_attr_tracker(t2).track(t2, t)) - // } - // ``` - // - // Where `foo_module_tracker` is a type tracker that tracks references to the `foo` module. - // Because named imports are modelled as `AttrRead`s, the statement `from foo import bar as baz` - // is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a - // reference to `foo.bar`, as desired. - exists(ImportExpr imp_expr | - not imp_expr.isRelative() and - imp_expr.getName() = name and - import_node.asCfgNode().getNode() = imp_expr and - // in `import foo.bar` we DON'T want to give a result for `importNode("foo.bar")`, - // only for `importNode("foo")`. We exclude those cases with the following clause. - not exists(Import imp | imp.getAName().getValue() = imp_expr) + private predicate imports(DataFlow::Node imp, string name) { + exists(ImportExprNode iexpr | + imp.asCfgNode() = iexpr and + not iexpr.getNode().isRelative() and + name = iexpr.getNode().getName() ) } From 07ffa9f1ae40041417d495f7b44e65de083dbd66 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 15:59:00 +0100 Subject: [PATCH 171/429] Python: More documentation --- python/ql/src/semmle/python/ApiGraphs.qll | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index dc658dcc2be..8a0d4dfd7ef 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -60,8 +60,10 @@ module API { /** * Gets a node representing member `m` of this API component. * - * For example, modules have an `exports` member representing their exports, and objects have - * their properties as members. + * For example, a member can be: + * + * - A submodule of a module + * - An attribute of an object */ bindingset[m] bindingset[result] @@ -235,7 +237,11 @@ module API { MkRoot() or /** An abstract representative for imports of the module called `name`. */ MkModuleImport(string name) { - imports(_, name) or name = any(ImportExpr e | not e.isRelative()).getAnImportedModuleName() + imports(_, name) + or + // When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes + // `foo` and `foo.bar`: + name = any(ImportExpr e | not e.isRelative()).getAnImportedModuleName() } or /** A use of an API member at the node `nd`. */ MkUse(DataFlow::Node nd) { use(_, _, nd) } From c1c9f963b913a0daca89984902ace5cdfa6030cf Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 12:34:48 +0100 Subject: [PATCH 172/429] C++: Fix qhelp in cpp/unsigned-difference-expression-compared-zero. --- ...UnsignedDifferenceExpressionComparedZero.c | 16 +++++---------- ...gnedDifferenceExpressionComparedZero.qhelp | 20 +++++++++---------- ...nsignedDifferenceExpressionComparedZero.ql | 8 ++++---- ...dDifferenceExpressionComparedZero.expected | 20 +++++++++---------- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c index f6054226848..d2f2b76fddc 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c +++ b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c @@ -1,11 +1,5 @@ -unsigned long sizeArray; - -// BAD: let's consider several values, taking ULONG_MAX =18446744073709551615 -// sizeArray = 60; (sizeArray - 10) = 50; true -// sizeArray = 10; (sizeArray - 10) = 0; false -// sizeArray = 1; (sizeArray - 10) = 18446744073709551607; true -// sizeArray = 0; (sizeArray - 10) = 18446744073709551606; true -if (sizeArray - 10 > 0) - -// GOOD: Prevent overflow by checking the input -if (sizeArray > 10) +unsigned limit = get_limit(); +unsigned total = 0; +while (limit - total > 0) { // wrong: if `total` is greater than `limit` this will underflow and continue executing the loop. + total += get_data(); +} \ No newline at end of file diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp index 3bf28d13df4..575d37d3c85 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp +++ b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp @@ -3,23 +3,21 @@ "qhelp.dtd"> -

    The code compares the unsigned difference with zero. -It is highly probable that the condition is wrong if the difference expression has the unsigned type. -The condition holds in all the cases when difference is not equal to zero. -It means that we may use condition not equal. But the programmer probably wanted to compare the difference of elements.

    - -

    False positives include code in which the first difference element is always greater than or equal to the second. -For comparison, ">" such conditions are equivalent to "! =", And are recommended for replacement. -For comparison "> =", the conditions are always true and are recommended to be excluded.

    - +

    +This rule finds relational comparisons between the result of an unsigned subtraction and the value 0. +Such comparisons are likely wrong as the value of an unsigned subtraction can never be negative. So the +relational comparison ends up checking whether the result of the subtraction is equal to 0. +This is likely not what the programmer intended. +

    -

    Use a simple comparison of two elements, instead of comparing their difference to zero.

    +

    If a relational comparison is intended, consider casting the result of the subtraction to a signed type. + If the intention was to test for equality, consider replacing the relational comparison with an equality test. +

    -

    The following example demonstrates an erroneous and corrected use of comparison.

    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql index 3de8ddefeaf..8bab534344d 100644 --- a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ b/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -1,13 +1,12 @@ /** * @name Unsigned difference expression compared to zero - * @description It is highly probable that the condition is wrong if the difference expression has the unsigned type. - * The condition holds in all the cases when difference is not equal to zero. It means that we may use condition not equal. - * But the programmer probably wanted to compare the difference of elements. + * @description A subtraction with an unsigned result can never be negative. Using such an expression in a relational comparison with `0` is likely to be wrong. * @kind problem * @id cpp/unsigned-difference-expression-compared-zero * @problem.severity warning * @precision medium * @tags security + * correctness * external/cwe/cwe-191 */ @@ -33,8 +32,9 @@ predicate nonNegative(SubExpr sub) { from RelationalOperation ro, SubExpr sub where not isFromMacroDefinition(ro) and + not isFromMacroDefinition(sub) and ro.getLesserOperand().getValue().toInt() = 0 and ro.getGreaterOperand() = sub and sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned() and not nonNegative(sub) -select ro, "Difference in condition is always greater than or equal to zero" +select ro, "Unsigned subtraction can never be negative." diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected index 6e1b80a4c8c..2d28795d126 100644 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected +++ b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected @@ -1,10 +1,10 @@ -| test.cpp:6:5:6:13 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:10:8:10:24 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:15:9:15:25 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:32:12:32:20 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:39:12:39:20 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:47:5:47:13 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:55:5:55:13 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:62:5:62:13 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:69:5:69:13 | ... > ... | Difference in condition is always greater than or equal to zero | -| test.cpp:75:8:75:16 | ... > ... | Difference in condition is always greater than or equal to zero | +| test.cpp:6:5:6:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:10:8:10:24 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:15:9:15:25 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:32:12:32:20 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:39:12:39:20 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:47:5:47:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:55:5:55:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:62:5:62:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:69:5:69:13 | ... > ... | Unsigned subtraction can never be negative. | +| test.cpp:75:8:75:16 | ... > ... | Unsigned subtraction can never be negative. | From fd596ebbbb773b17028f3fce165a94cb2ff7df58 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 16:00:56 +0100 Subject: [PATCH 173/429] C++: Move cpp/unsigned-difference-expression-compared-zero out of experimental. --- .../CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c | 0 .../CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp | 0 .../CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql | 0 .../UnsignedDifferenceExpressionComparedZero.qlref | 1 - .../UnsignedDifferenceExpressionComparedZero.expected | 0 .../UnsignedDifferenceExpressionComparedZero.qlref | 1 + .../CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp | 0 7 files changed, 1 insertion(+), 1 deletion(-) rename cpp/ql/src/{experimental => }/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c (100%) rename cpp/ql/src/{experimental => }/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp (100%) rename cpp/ql/src/{experimental => }/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql (100%) delete mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref rename cpp/ql/test/{experimental => }/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected (100%) create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref rename cpp/ql/test/{experimental => }/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp (100%) diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c similarity index 100% rename from cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c rename to cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.c diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp similarity index 100% rename from cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp rename to cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql similarity index 100% rename from cpp/ql/src/experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql rename to cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref deleted file mode 100644 index 2d15983a540..00000000000 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected similarity index 100% rename from cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected rename to cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.expected diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref new file mode 100644 index 00000000000..9681978c0ad --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/UnsignedDifferenceExpressionComparedZero.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp similarity index 100% rename from cpp/ql/test/experimental/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp rename to cpp/ql/test/query-tests/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero/test.cpp From 707f532e107f5b6873b94850a097f2266171088b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 16:01:28 +0100 Subject: [PATCH 174/429] C++: Fix bad join-order using a poor man's unbind operator. --- ...UnsignedDifferenceExpressionComparedZero.ql | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql index 8bab534344d..36f2390e995 100644 --- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -16,16 +16,24 @@ import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import semmle.code.cpp.controlflow.Guards +/** Holds if `sub` is guarded by a condition which ensures that `left >= right`. */ +pragma[noinline] +predicate isGuarded(SubExpr sub, Expr left, Expr right) { + exists(GuardCondition guard | + guard.controls(sub.getBasicBlock(), true) and + guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false) + ) +} + /** Holds if `sub` will never be negative. */ predicate nonNegative(SubExpr sub) { not exprMightOverflowNegatively(sub.getFullyConverted()) or // The subtraction is guarded by a check of the form `left >= right`. - exists(GuardCondition guard, Expr left, Expr right | - left = globalValueNumber(sub.getLeftOperand()).getAnExpr() and - right = globalValueNumber(sub.getRightOperand()).getAnExpr() and - guard.controls(sub.getBasicBlock(), true) and - guard.ensuresLt(left, right, 0, sub.getBasicBlock(), false) + exists(GVN left, GVN right | + strictcount([left, globalValueNumber(sub.getLeftOperand())]) = 1 and + strictcount([right, globalValueNumber(sub.getRightOperand())]) = 1 and + isGuarded(sub, left.getAnExpr(), right.getAnExpr()) ) } From d9d82fc56aa6f2e9412af86a676ee0e601d9bbfa Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 16:24:56 +0100 Subject: [PATCH 175/429] C++: Update change-notes --- .../2020-02-04-unsigned-difference-expression-compared-zero.md | 2 ++ cpp/config/suites/cpp/correctness | 1 + 2 files changed, 3 insertions(+) create mode 100644 cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md diff --git a/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md new file mode 100644 index 00000000000..e2726b5b574 --- /dev/null +++ b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md @@ -0,0 +1,2 @@ +lgtm +* A new query (`cpp/unsigned-difference-expression-compared-zero`) has been added. The query finds unsigned subtractions used in relational comparisons with the value 0. \ No newline at end of file diff --git a/cpp/config/suites/cpp/correctness b/cpp/config/suites/cpp/correctness index bcdf94c94ce..55678a1dd37 100644 --- a/cpp/config/suites/cpp/correctness +++ b/cpp/config/suites/cpp/correctness @@ -10,6 +10,7 @@ + semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/OO/UnsafeUseOfThis.ql: /Correctness/Dangerous Conversions ++ semmlecode-cpp-queries/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql: /Correctness/Dangerous Conversions # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use From 305bfaba2d5e2de09ff0558e6f24d098be2fa19e Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 16:46:22 +0100 Subject: [PATCH 176/429] Python: Fix `imports/2` --- python/ql/src/semmle/python/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 8a0d4dfd7ef..02cf31fc669 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -273,7 +273,7 @@ module API { exists(ImportExprNode iexpr | imp.asCfgNode() = iexpr and not iexpr.getNode().isRelative() and - name = iexpr.getNode().getName() + name = iexpr.getNode().getImportedModuleName() ) } From 161e5679a741753695827cc4ac9f1613f5eede18 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 16:47:45 +0100 Subject: [PATCH 177/429] Apply suggestions from code review Co-authored-by: hubwriter --- .../CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp index 575d37d3c85..965429bda8a 100644 --- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.qhelp @@ -5,9 +5,9 @@

    This rule finds relational comparisons between the result of an unsigned subtraction and the value 0. -Such comparisons are likely wrong as the value of an unsigned subtraction can never be negative. So the +Such comparisons are likely to be wrong as the value of an unsigned subtraction can never be negative. So the relational comparison ends up checking whether the result of the subtraction is equal to 0. -This is likely not what the programmer intended. +This is probably not what the programmer intended.

    @@ -23,7 +23,7 @@ This is likely not what the programmer intended.
    -
  • CERT C Coding Standard: +
  • SEI CERT C Coding Standard: INT02-C. Understand integer conversion rules.
  • From 9d06c75aed2b707645387e1fd942dddba3ba4c7b Mon Sep 17 00:00:00 2001 From: alexet Date: Thu, 4 Feb 2021 15:48:10 +0000 Subject: [PATCH 178/429] Javascript: improve performance of ExplicitInvokeNode::getArgument --- .../ql/src/semmle/javascript/dataflow/DataFlow.qll | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index a2b2d2deb66..f07a40e4f7e 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -1079,8 +1079,19 @@ module DataFlow { override DataFlow::Node getCalleeNode() { result = DataFlow::valueNode(astNode.getCallee()) } + /** + * Whether i is an index that occurs after a spread argument. + */ + pragma[nomagic] + private predicate isIndexAfterSpread(int i) { + astNode.isSpreadArgument(i) + or + exists(astNode.getArgument(i)) and + isIndexAfterSpread(i - 1) + } + override DataFlow::Node getArgument(int i) { - not astNode.isSpreadArgument([0 .. i]) and + not isIndexAfterSpread(i) and result = DataFlow::valueNode(astNode.getArgument(i)) } From 6a97d02247578ee82fc03712918d957eee29ec8b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 17:24:14 +0100 Subject: [PATCH 179/429] C++: Address review comments. --- .../CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql index 36f2390e995..007a4fd746d 100644 --- a/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql +++ b/cpp/ql/src/Security/CWE/CWE-191/UnsignedDifferenceExpressionComparedZero.ql @@ -31,6 +31,7 @@ predicate nonNegative(SubExpr sub) { or // The subtraction is guarded by a check of the form `left >= right`. exists(GVN left, GVN right | + // This is basically a poor man's version of a directional unbind operator. strictcount([left, globalValueNumber(sub.getLeftOperand())]) = 1 and strictcount([right, globalValueNumber(sub.getRightOperand())]) = 1 and isGuarded(sub, left.getAnExpr(), right.getAnExpr()) From aa7e9f0b56357d0446e7299869c67a419803fb53 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 18:00:57 +0100 Subject: [PATCH 180/429] Python: Add big explanatory comment about prefixes. --- python/ql/src/semmle/python/ApiGraphs.qll | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 02cf31fc669..cb78e3eb9ce 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -231,6 +231,60 @@ module API { */ cached private module Impl { + /* + * Modeling imports is slightly tricky because of the way we handle dotted name imports in our + * libraries. In dotted imports such as + * + * ```python + * import foo.bar.baz as fbb + * from foo.bar.baz import quux as fbbq + * ``` + * + * the dotted name is simply represented as a string. We would like `fbb.quux` and `fbbq` to + * be represented as API graph nodes with the following path: + * + * ```ql + * moduleImport("foo").getMember("bar").getMember("baz").getMember("quux") + * ``` + * + * To do this, we produce an API graph node for each dotted name prefix we find in the set of + * imports. Thus, for the above two imports, we would get nodes for + * + * ```python + * foo + * foo.bar + * foo.bar.baz + * ``` + * + * Only the first of these can act as the beginning of a path (and become a + * `moduleImport`-labeled edge from the global root node). + * + * (Using prefixes rather than simply `foo`, `bar`, and `baz` is important. We don't want + * potential crosstalk between `foo.bar.baz` and `ham.bar.eggs`.) + * + * We then add `getMember` edges between these prefixes: `foo` steps to `foo.bar` via an edge + * labeled `getMember("bar")` and so on. + * + * When we then see `import foo.bar.baz as fbb`, the data-flow node `fbb` gets marked as a use + * of the API graph node corresponding to the prefix `foo.bar.baz`. Because of the edges leading to + * this node, it is reachable via `moduleImport("foo").getMember("bar").getMember("baz")` and + * thus `fbb.quux` is reachable via the path mentioned above. + * + * When we see `from foo.bar.baz import quux as fbb` a similar thing happens. First, `foo.bar.baz` + * is seen as a use of the API graph node as before. Then `import quux as fbbq` is seen as + * a member lookup of `quux` on the API graph node for `foo.bar.baz`, and then finally the + * data-flow node `fbbq` is marked as a use of the same path mentioned above. + * + * Finally, in a non-aliased import such as + * + * ```python + * import foo.bar.baz + * ``` + * + * we only consider this as a definition of the name `foo` (thus making it a use of the corresponding + * API graph node for the prefix `foo`), in accordance with the usual semantics of Python. + */ + cached newtype TApiNode = /** The root of the API graph. */ From 2524f23a46e2c4194fcb9619aa084f5c373ea003 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 18:05:33 +0100 Subject: [PATCH 181/429] Python: Add more test cases There is now a bit of redundancy in the tests, but I thought it useful to actually include some of the cases called out explicitly in the documentation, so as to make it easy to see that the code actually does what we expect (in these cases, anyway). --- .../test/experimental/dataflow/ApiGraphs/test.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py index 8137066ad6f..27888cd9f9e 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -28,6 +28,14 @@ from a6 import m6 #$ use=moduleImport("a6").getMember("m6") x6 = m6().foo().bar() #$ use=moduleImport("a6").getMember("m6").getReturn().getMember("foo").getReturn().getMember("bar").getReturn() +import foo.baz.baz as fbb #$ use=moduleImport("foo").getMember("baz").getMember("baz") +from foo.bar.baz import quux as fbbq #$ use=moduleImport("foo").getMember("bar").getMember("baz").getMember("quux") +from ham.bar.eggs import spam as hbes #$ use=moduleImport("ham").getMember("bar").getMember("eggs").getMember("spam") +fbb.quux #$ use=moduleImport("foo").getMember("baz").getMember("baz").getMember("quux") +fbbq #$ use=moduleImport("foo").getMember("bar").getMember("baz").getMember("quux") +hbes #$ use=moduleImport("ham").getMember("bar").getMember("eggs").getMember("spam") + +import foo.bar.baz #$ use=moduleImport("foo") # Relative imports. These are ignored @@ -65,3 +73,9 @@ def f(): foo = NONSOURCE change_foo() sink(foo) #$ MISSING: use=moduleImport("danger").getMember("SOURCE") + +# Star imports + +from unknown import * #$ use=moduleImport("unknown") + +hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn() From f6e1ea5b2adcd367ac2b01216dec472c4f070040 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 18:07:13 +0100 Subject: [PATCH 182/429] Python: Fix missing global variable source nodes In lieu of removing the offending flow (which would likely have consequences for a lot of other tests), I opted to simply _include_ the relevant nodes directly. --- .../src/semmle/python/dataflow/new/internal/DataFlowPublic.qll | 2 ++ python/ql/test/experimental/dataflow/ApiGraphs/test.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index b2e2298182e..dcc175276f8 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -446,6 +446,8 @@ class LocalSourceNode extends Node { LocalSourceNode() { not simpleLocalFlowStep+(any(CfgNode n), this) and not this instanceof ModuleVariableNode + or + this = any(ModuleVariableNode mvn).getARead() } /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py index 27888cd9f9e..b250c7985e2 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -72,7 +72,7 @@ def f(): sink(foo) #$ use=moduleImport("danger").getMember("SOURCE") foo = NONSOURCE change_foo() - sink(foo) #$ MISSING: use=moduleImport("danger").getMember("SOURCE") + sink(foo) #$ use=moduleImport("danger").getMember("SOURCE") # Star imports From 4b9532c6f7cb6bcb5f7b35d724d9c39a0943095f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 18 Sep 2019 10:35:42 +0100 Subject: [PATCH 183/429] CPP: Examples Namespace.qll. --- cpp/ql/src/semmle/code/cpp/Namespace.qll | 43 +++++++++++++++++++----- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Namespace.qll b/cpp/ql/src/semmle/code/cpp/Namespace.qll index 6172c3af50c..d46abc6b4db 100644 --- a/cpp/ql/src/semmle/code/cpp/Namespace.qll +++ b/cpp/ql/src/semmle/code/cpp/Namespace.qll @@ -7,8 +7,21 @@ import semmle.code.cpp.Type import semmle.code.cpp.metrics.MetricNamespace /** - * A C++ namespace. + * A C++ namespace. For example the (single) namespace `A` in the following + * code: + * ``` + * namespace A + * { + * // ... + * } * + * // ... + * + * namespace A + * { + * // ... + * } + * ``` * Note that namespaces are somewhat nebulous entities, as they do not in * general have a single well-defined location in the source code. The * related notion of a `NamespaceDeclarationEntry` is rather more concrete, @@ -96,10 +109,22 @@ class Namespace extends NameQualifyingElement, @namespace { } /** - * A declaration of (part of) a C++ namespace. + * A declaration of (part of) a C++ namespace. This corresponds to a single + * `namespace N { ... }` occurrence in the source code. For example the two + * mentions of `A` in the following code: + * ``` + * namespace A + * { + * // ... + * } * - * This corresponds to a single `namespace N { ... }` occurrence in the - * source code. + * // ... + * + * namespace A + * { + * // ... + * } + * ``` */ class NamespaceDeclarationEntry extends Locatable, @namespace_decl { /** @@ -143,8 +168,9 @@ class UsingEntry extends Locatable, @using { /** * A C++ `using` declaration. For example: - * - * `using std::string;` + * ``` + * using std::string; + * ``` */ class UsingDeclarationEntry extends UsingEntry { UsingDeclarationEntry() { @@ -162,8 +188,9 @@ class UsingDeclarationEntry extends UsingEntry { /** * A C++ `using` directive. For example: - * - * `using namespace std;` + * ``` + * using namespace std; + * ``` */ class UsingDirectiveEntry extends UsingEntry { UsingDirectiveEntry() { From 500097ca76e0abce3d47a414b720d0be01b78ed9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 18 Sep 2019 16:03:35 +0100 Subject: [PATCH 184/429] CPP: Examples Preprocessor.qll. --- cpp/ql/src/semmle/code/cpp/Preprocessor.qll | 104 ++++++++++++++++---- 1 file changed, 84 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll index a9609922b74..2389db07f2a 100644 --- a/cpp/ql/src/semmle/code/cpp/Preprocessor.qll +++ b/cpp/ql/src/semmle/code/cpp/Preprocessor.qll @@ -2,9 +2,14 @@ import semmle.code.cpp.Location import semmle.code.cpp.Element /** - * A C/C++ preprocessor directive. - * - * For example: `#ifdef`, `#line`, or `#pragma`. + * A C/C++ preprocessor directive. For example each of the following lines of + * code contains a `PreprocessorDirective`: + * ``` + * #pragma once + * #ifdef MYDEFINE + * #include "myfile.h" + * #line 1 "source.c" + * ``` */ class PreprocessorDirective extends Locatable, @preprocdirect { override string toString() { result = "Preprocessor directive" } @@ -98,9 +103,9 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr * A C/C++ preprocessor branching directive: `#if`, `#ifdef`, `#ifndef`, or * `#elif`. * - * A branching directive can have its condition evaluated at compile-time, - * and as a result, the preprocessor will either take the branch, or not - * take the branch. + * A branching directive has a condition and that condition may be evaluated + * at compile-time. As a result, the preprocessor will either take the + * branch, or not take the branch. * * However, there are also situations in which a branch's condition isn't * evaluated. The obvious case of this is when the directive is contained @@ -136,8 +141,13 @@ class PreprocessorBranch extends PreprocessorBranchDirective, @ppd_branch { } /** - * A C/C++ preprocessor `#if` directive. - * + * A C/C++ preprocessor `#if` directive. For example there is a + * `PreprocessorIf` on the first line of the following code: + * ``` + * #if defined(MYDEFINE) + * // ... + * #endif + * ``` * For the related notion of a directive which causes branching (which * includes `#if`, plus also `#ifdef`, `#ifndef`, and `#elif`), see * `PreprocessorBranch`. @@ -147,8 +157,13 @@ class PreprocessorIf extends PreprocessorBranch, @ppd_if { } /** - * A C/C++ preprocessor `#ifdef` directive. - * + * A C/C++ preprocessor `#ifdef` directive. For example there is a + * `PreprocessorIfdef` on the first line of the following code: + * ``` + * #ifdef MYDEFINE + * // ... + * #endif + * ``` * The syntax `#ifdef X` is shorthand for `#if defined(X)`. */ class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { @@ -158,8 +173,13 @@ class PreprocessorIfdef extends PreprocessorBranch, @ppd_ifdef { } /** - * A C/C++ preprocessor `#ifndef` directive. - * + * A C/C++ preprocessor `#ifndef` directive. For example there is a + * `PreprocessorIfndef` on the first line of the following code: + * ``` + * #ifndef MYDEFINE + * // ... + * #endif + * ``` * The syntax `#ifndef X` is shorthand for `#if !defined(X)`. */ class PreprocessorIfndef extends PreprocessorBranch, @ppd_ifndef { @@ -167,42 +187,80 @@ class PreprocessorIfndef extends PreprocessorBranch, @ppd_ifndef { } /** - * A C/C++ preprocessor `#else` directive. + * A C/C++ preprocessor `#else` directive. For example there is a + * `PreprocessorElse` on the fifth line of the following code: + * ``` + * #ifdef MYDEFINE1 + * // ... + * #elif MYDEFINE2 + * // ... + * #else + * // ... + * #endif + * ``` */ class PreprocessorElse extends PreprocessorBranchDirective, @ppd_else { override string toString() { result = "#else" } } /** - * A C/C++ preprocessor `#elif` directive. + * A C/C++ preprocessor `#elif` directive. For example there is a + * `PreprocessorElif` on the third line of the following code: + * ``` + * #ifdef MYDEFINE1 + * // ... + * #elif MYDEFINE2 + * // ... + * #else + * // ... + * #endif + * ``` */ class PreprocessorElif extends PreprocessorBranch, @ppd_elif { override string toString() { result = "#elif " + this.getHead() } } /** - * A C/C++ preprocessor `#endif` directive. + * A C/C++ preprocessor `#endif` directive. For example there is a + * `PreprocessorEndif` on the third line of the following code: + * ``` + * #ifdef MYDEFINE + * // ... + * #endif + * ``` */ class PreprocessorEndif extends PreprocessorBranchDirective, @ppd_endif { override string toString() { result = "#endif" } } /** - * A C/C++ preprocessor `#warning` directive. + * A C/C++ preprocessor `#warning` directive. For example: + * ``` + * #warning "This configuration is not supported." + * ``` */ class PreprocessorWarning extends PreprocessorDirective, @ppd_warning { override string toString() { result = "#warning " + this.getHead() } } /** - * A C/C++ preprocessor `#error` directive. + * A C/C++ preprocessor `#error` directive. For example: + * ``` + * #error "This configuration is not implemented." + * ``` */ class PreprocessorError extends PreprocessorDirective, @ppd_error { override string toString() { result = "#error " + this.getHead() } } /** - * A C/C++ preprocessor `#undef` directive. + * A C/C++ preprocessor `#undef` directive. For example there is a + * `PreprocessorUndef` on the second line of the following code: + * ``` + * #ifdef MYMACRO + * #undef MYMACRO + * #endif + * ``` */ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef { override string toString() { result = "#undef " + this.getHead() } @@ -214,7 +272,10 @@ class PreprocessorUndef extends PreprocessorDirective, @ppd_undef { } /** - * A C/C++ preprocessor `#pragma` directive. + * A C/C++ preprocessor `#pragma` directive. For example: + * ``` + * #pragma once + * ``` */ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma { override string toString() { @@ -223,7 +284,10 @@ class PreprocessorPragma extends PreprocessorDirective, @ppd_pragma { } /** - * A C/C++ preprocessor `#line` directive. + * A C/C++ preprocessor `#line` directive. For example: + * ``` + * #line 1 "source.c" + * ``` */ class PreprocessorLine extends PreprocessorDirective, @ppd_line { override string toString() { result = "#line " + this.getHead() } From 8ae01789b11923a82386257bda90c2855657c5b0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 19 Sep 2019 09:44:22 +0100 Subject: [PATCH 185/429] CPP: Examples Specifier.qll. --- cpp/ql/src/semmle/code/cpp/Specifier.qll | 39 +++++++++++++++++++----- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index 3d68fb374f1..43e6ef5d83c 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -29,6 +29,7 @@ class Specifier extends Element, @specifier { /** * A C/C++ function specifier: `inline`, `virtual`, or `explicit`. + * TODO */ class FunctionSpecifier extends Specifier { FunctionSpecifier() { @@ -43,6 +44,7 @@ class FunctionSpecifier extends Specifier { /** * A C/C++ storage class specifier: `auto`, `register`, `static`, `extern`, * or `mutable". + * TODO */ class StorageClassSpecifier extends Specifier { StorageClassSpecifier() { @@ -58,6 +60,7 @@ class StorageClassSpecifier extends Specifier { /** * A C++ access specifier: `public`, `protected`, or `private`. + * TODO */ class AccessSpecifier extends Specifier { AccessSpecifier() { @@ -146,12 +149,14 @@ class Attribute extends Element, @attribute { /** * An attribute introduced by GNU's `__attribute__((name))` syntax, for * example: `__attribute__((__noreturn__))`. + * TODO */ class GnuAttribute extends Attribute, @gnuattribute { } /** * An attribute introduced by the C++11 standard `[[name]]` syntax, for * example: `[[clang::fallthrough]]`. + * TODO */ class StdAttribute extends Attribute, @stdattribute { /** @@ -171,13 +176,20 @@ class StdAttribute extends Attribute, @stdattribute { } /** - * An attribute introduced by Microsoft's `__declspec(name)` syntax, for - * example: `__declspec(dllimport)`. + * An attribute introduced by Microsoft's `__declspec(name)` syntax. For + * example the attribute on the following declaration: + * ``` + * __declspec(dllimport) void myFunction(); + * ``` */ class Declspec extends Attribute, @declspec { } /** - * An attribute introduced by Microsoft's "[name]" syntax, for example "[SA_Pre(Deref=1,Access=SA_Read)]". + * An attribute introduced by Microsoft's "[name]" syntax. For example + * ``` + * [SA_Pre(Deref=1,Access=SA_Read)] + * TODO + * ``` */ class MicrosoftAttribute extends Attribute, @msattribute { AttributeArgument getNamedArgument(string name) { @@ -186,8 +198,13 @@ class MicrosoftAttribute extends Attribute, @msattribute { } /** - * A C++11 `alignas` construct. - * + * A C++11 `alignas` construct. For example the attribute in the following + * code: + * ``` + * struct alignas(16) MyStruct { + * int x; + * }; + * ``` * Though it doesn't use the attribute syntax, `alignas(...)` is presented * as an `Attribute` for consistency with the `[[align(...)]]` attribute. */ @@ -197,7 +214,11 @@ class AlignAs extends Attribute, @alignas { /** * A GNU `format` attribute of the form `__attribute__((format(archetype, format-index, first-arg)))` - * that declares a function to accept a `printf` style format string. + * that declares a function to accept a `printf` style format string. For example the attribute + * on the following declaration: + * ``` + * int myPrintf(const char *format, ...) __attribute__((format(printf, 1, 2))); + * ``` */ class FormatAttribute extends GnuAttribute { FormatAttribute() { getName() = "format" } @@ -242,7 +263,11 @@ class FormatAttribute extends GnuAttribute { } /** - * An argument to an `Attribute`. + * An argument to an `Attribute`. For example the argument "dllimport" on the + * attribute in the following code: + * ``` + * __declspec(dllimport) void myFunction(); + * ``` */ class AttributeArgument extends Element, @attribute_arg { /** From 1f928c29104cde7db37bb7ff8fa2dcb277b1af5e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 26 Sep 2019 17:23:45 +0100 Subject: [PATCH 186/429] CPP: Examples Element.qll. --- cpp/ql/src/semmle/code/cpp/Element.qll | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index f4c1bd972c6..66f23ea110f 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -270,7 +270,12 @@ private predicate isFromUninstantiatedTemplateRec(Element e, Element template) { } /** - * A C++11 `static_assert` or C11 `_Static_assert` construct. + * A C++11 `static_assert` or C11 `_Static_assert` construct. For example each + * line in the following example contains a static assert: + * ``` + * static_assert(sizeof(MyStruct) <= 4096); + * static_assert(sizeof(MyStruct) <= 4096, "MyStruct is too big!"); + * ``` */ class StaticAssert extends Locatable, @static_assert { override string toString() { result = "static_assert(..., \"" + getMessage() + "\")" } From 2160edc789d21bb398e6cee28730490025a55101 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 4 Feb 2021 17:14:49 +0000 Subject: [PATCH 187/429] C++: Clean up bits I didn't finish. --- cpp/ql/src/semmle/code/cpp/Specifier.qll | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index 43e6ef5d83c..8331d0dfacc 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -29,7 +29,6 @@ class Specifier extends Element, @specifier { /** * A C/C++ function specifier: `inline`, `virtual`, or `explicit`. - * TODO */ class FunctionSpecifier extends Specifier { FunctionSpecifier() { @@ -44,7 +43,6 @@ class FunctionSpecifier extends Specifier { /** * A C/C++ storage class specifier: `auto`, `register`, `static`, `extern`, * or `mutable". - * TODO */ class StorageClassSpecifier extends Specifier { StorageClassSpecifier() { @@ -60,7 +58,6 @@ class StorageClassSpecifier extends Specifier { /** * A C++ access specifier: `public`, `protected`, or `private`. - * TODO */ class AccessSpecifier extends Specifier { AccessSpecifier() { @@ -149,14 +146,12 @@ class Attribute extends Element, @attribute { /** * An attribute introduced by GNU's `__attribute__((name))` syntax, for * example: `__attribute__((__noreturn__))`. - * TODO */ class GnuAttribute extends Attribute, @gnuattribute { } /** * An attribute introduced by the C++11 standard `[[name]]` syntax, for * example: `[[clang::fallthrough]]`. - * TODO */ class StdAttribute extends Attribute, @stdattribute { /** @@ -185,11 +180,7 @@ class StdAttribute extends Attribute, @stdattribute { class Declspec extends Attribute, @declspec { } /** - * An attribute introduced by Microsoft's "[name]" syntax. For example - * ``` - * [SA_Pre(Deref=1,Access=SA_Read)] - * TODO - * ``` + * An attribute introduced by Microsoft's "[name]" syntax, for example "[SA_Pre(Deref=1,Access=SA_Read)]". */ class MicrosoftAttribute extends Attribute, @msattribute { AttributeArgument getNamedArgument(string name) { From 3c7d9c3c4b5aac34ee2f777ce47734954baeeccb Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 18:33:50 +0100 Subject: [PATCH 188/429] Python: Fix typo --- python/ql/src/semmle/python/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index cb78e3eb9ce..0fc92f22c94 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -88,7 +88,7 @@ module API { * Gets a node representing the result of the function represented by this node. * * This predicate may have multiple results when there are multiple invocations of this API component. - * Consider using `getACall()` if there is a need to distingiush between individual calls. + * Consider using `getACall()` if there is a need to distinguish between individual calls. */ Node getReturn() { result = getASuccessor(Label::return()) } From a505eb692237e540171e3b17f1b23149c2388d3f Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 18:34:06 +0100 Subject: [PATCH 189/429] Python: Adhere to QLDoc style guide --- python/ql/src/semmle/python/ApiGraphs.qll | 26 +++++++++++++---------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 0fc92f22c94..6bacac72c3a 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -128,25 +128,29 @@ module API { DataFlow::Node getInducingNode() { this = Impl::MkUse(result) } /** - * Holds if this node is located in file `path` between line `startline`, column `startcol`, - * and line `endline`, column `endcol`. - * - * For nodes that do not have a meaningful location, `path` is the empty string and all other - * parameters are zero. + * Holds if this element is at the specified location. + * The location spans column `startcolumn` of line `startline` to + * column `endcolumn` of line `endline` in file `filepath`. + * For more information, see + * [Locations](https://help.semmle.com/QL/learn-ql/locations.html). */ - predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) { - getInducingNode().hasLocationInfo(path, startline, startcol, endline, endcol) + predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + getInducingNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) or + // For nodes that do not have a meaningful location, `path` is the empty string and all other + // parameters are zero. not exists(getInducingNode()) and - path = "" and + filepath = "" and startline = 0 and - startcol = 0 and + startcolumn = 0 and endline = 0 and - endcol = 0 + endcolumn = 0 } /** - * Gets a textual representation of this node. + * Gets a textual representation of this element. */ abstract string toString(); From d0359370837c53e3905504ee3141b56da78817a3 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 4 Feb 2021 18:43:44 +0100 Subject: [PATCH 190/429] Python: Add change note --- python/change-notes/2021-02-04-api-graphs.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 python/change-notes/2021-02-04-api-graphs.md diff --git a/python/change-notes/2021-02-04-api-graphs.md b/python/change-notes/2021-02-04-api-graphs.md new file mode 100644 index 00000000000..533a4b17c5a --- /dev/null +++ b/python/change-notes/2021-02-04-api-graphs.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added support for API graphs. Data-flow nodes referring to an external API component such as `flask.views.View` can now be found using `API::moduleImport("flask").getMember("views").getMember("View").getAUse()` when the `semmle.python.ApiGraphs` module has been imported. \ No newline at end of file From 979fdd2c6a9fe011d1ee43dce9e09e3c03da292d Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 4 Feb 2021 10:23:01 -0800 Subject: [PATCH 191/429] Addressing multiple comments --- .../backdoor/DangerousNativeFunctionCall.ql | 1 + .../Security Features/backdoor/PotentialTimeBomb.qhelp | 8 ++++++++ .../backdoor/ProcessNameToHashTaintFlow.qhelp | 2 +- .../backdoor/ProcessNameToHashTaintFlow.ql | 1 + ...Detection.qhelp => ModifiedFnvFunctionDetection.qhelp} | 0 ...nctionDetection.ql => ModifiedFnvFunctionDetection.ql} | 0 6 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp rename csharp/ql/src/experimental/Security Features/campaign/Solorigate/{ModifedFnvFunctionDetection.qhelp => ModifiedFnvFunctionDetection.qhelp} (100%) rename csharp/ql/src/experimental/Security Features/campaign/Solorigate/{ModifedFnvFunctionDetection.ql => ModifiedFnvFunctionDetection.ql} (100%) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql index cc8f0bda367..f36f5b6ee2a 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql @@ -1,6 +1,7 @@ /** * @name Potential dangerous use of native functions * @description Please review code for possible malicious intent or unsafe handling. + * NOTE: This query is an example of a query that may be useful for detecting potential backdoors, and Solorigate is just one such example that uses this mechanism. * @kind problem * @problem.severity warning * @precision low diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp new file mode 100644 index 00000000000..32f0e200c15 --- /dev/null +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp @@ -0,0 +1,8 @@ + + + +

    This query finds if there exists a DataFlow from a file last modification date (very likely implant installation time) and an offset to a condition statement (the trigger) that controls code execution.

    +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp index 39d21b32b72..7281ddb28bb 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp @@ -3,7 +3,7 @@ "qhelp.dtd"> -

    This query detects code flow from PorcessName property on the Process class into a hash function.

    +

    This query detects code flow from ProcessName property on the Process class into a hash function.

    Such flow is often used in code backdoors to detect runnig processes and compare them to an obfuscated list of antivirus processes to aviod detection.

    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql index 4b1c657eff3..5b1f8faeaf6 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -1,6 +1,7 @@ /** * @name ProcessName to hash function flow * @description Flow from a function retrieving process name to a hash function + * NOTE: This query is an example of a query that may be useful for detecting potential backdoors, and Solorigate is just one such example that uses this mechanism. * @kind problem * @tags security * solorigate diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp similarity index 100% rename from csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.qhelp rename to csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql similarity index 100% rename from csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifedFnvFunctionDetection.ql rename to csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql From 993abd44993b16a0e5941afc73f0a250777eeda0 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 4 Feb 2021 20:23:27 +0100 Subject: [PATCH 192/429] C++: Add query author and link to original PR in change-note. --- .../2020-02-04-unsigned-difference-expression-compared-zero.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md index e2726b5b574..31f2b035267 100644 --- a/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md +++ b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md @@ -1,2 +1,2 @@ lgtm -* A new query (`cpp/unsigned-difference-expression-compared-zero`) has been added. The query finds unsigned subtractions used in relational comparisons with the value 0. \ No newline at end of file +* A new query (`cpp/unsigned-difference-expression-compared-zero`) has been added. The query finds unsigned subtractions used in relational comparisons with the value 0. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4745. \ No newline at end of file From a6fd7a3203f564015a9cc35f7fbb2cc99f6720cc Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 18 Nov 2020 15:48:05 +0100 Subject: [PATCH 193/429] C#: Extract record declarations --- .../Populators/TypeContainerVisitor.cs | 5 + csharp/ql/src/semmle/code/csharp/PrintAst.qll | 7 +- .../library-tests/csharp9/InitOnlyProperty.cs | 7 - .../library-tests/csharp9/IsExternalInit.cs | 7 + .../library-tests/csharp9/PrintAst.expected | 429 +++++++++++++++--- .../ql/test/library-tests/csharp9/Record.cs | 72 +++ .../csharp9/initOnlyProperty.expected | 15 +- .../library-tests/csharp9/record.expected | 212 +++++++++ .../ql/test/library-tests/csharp9/record.ql | 18 + 9 files changed, 684 insertions(+), 88 deletions(-) create mode 100644 csharp/ql/test/library-tests/csharp9/IsExternalInit.cs create mode 100644 csharp/ql/test/library-tests/csharp9/Record.cs create mode 100644 csharp/ql/test/library-tests/csharp9/record.expected create mode 100644 csharp/ql/test/library-tests/csharp9/record.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs index a45ede39501..6e5b45e9e3a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs @@ -43,6 +43,11 @@ namespace Semmle.Extraction.CSharp.Populators Entities.NamedType.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); } + public override void VisitRecordDeclaration(RecordDeclarationSyntax node) + { + Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); + } + public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl) { Entities.Type.Create(cx, cx.GetModel(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(trapFile, parent); diff --git a/csharp/ql/src/semmle/code/csharp/PrintAst.qll b/csharp/ql/src/semmle/code/csharp/PrintAst.qll index a4ab6f7632c..f623860ff2d 100644 --- a/csharp/ql/src/semmle/code/csharp/PrintAst.qll +++ b/csharp/ql/src/semmle/code/csharp/PrintAst.qll @@ -102,15 +102,16 @@ private ValueOrRefType getAnInterestingBaseType(ValueOrRefType type) { not type instanceof ArrayType and not type instanceof NullableType and result = type.getABaseType() and - isInterestingBaseType(result) + isInterestingBaseType(type, result) } -private predicate isInterestingBaseType(ValueOrRefType base) { +private predicate isInterestingBaseType(ValueOrRefType type, ValueOrRefType base) { not base instanceof ObjectType and not base.getQualifiedName() = "System.ValueType" and not base.getQualifiedName() = "System.Delegate" and not base.getQualifiedName() = "System.MulticastDelegate" and - not base.getQualifiedName() = "System.Enum" + not base.getQualifiedName() = "System.Enum" and + exists(TypeMention tm | tm.getTarget() = type and tm.getType() = base) } /** diff --git a/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs b/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs index bb78e0790af..e5a27113566 100644 --- a/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs +++ b/csharp/ql/test/library-tests/csharp9/InitOnlyProperty.cs @@ -1,12 +1,5 @@ using System; -namespace System.Runtime.CompilerServices -{ - public sealed class IsExternalInit - { - } -} - public class Base { public int Prop0 { get { return 1; } init { Prop1 = value; } } diff --git a/csharp/ql/test/library-tests/csharp9/IsExternalInit.cs b/csharp/ql/test/library-tests/csharp9/IsExternalInit.cs new file mode 100644 index 00000000000..354491fdec2 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/IsExternalInit.cs @@ -0,0 +1,7 @@ +using System; +using System.Text; + +namespace System.Runtime.CompilerServices +{ + public class IsExternalInit { } +} diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index ef30aa13ece..4d4288d3649 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -287,87 +287,88 @@ FunctionPointer.cs: #-----| 3: (Base types) # 50| 0: [TypeMention] A InitOnlyProperty.cs: -# 3| [NamespaceDeclaration] namespace ... { ... } -# 5| 1: [Class] IsExternalInit -# 10| [Class] Base -# 12| 5: [Property] Prop0 -# 12| -1: [TypeMention] int -# 12| 3: [Getter] get_Prop0 -# 12| 4: [BlockStmt] {...} -# 12| 0: [ReturnStmt] return ...; -# 12| 0: [IntLiteral] 1 -# 12| 4: [Setter] set_Prop0 +# 3| [Class] Base +# 5| 5: [Property] Prop0 +# 5| -1: [TypeMention] int +# 5| 3: [Getter] get_Prop0 +# 5| 4: [BlockStmt] {...} +# 5| 0: [ReturnStmt] return ...; +# 5| 0: [IntLiteral] 1 +# 5| 4: [Setter] set_Prop0 #-----| 2: (Parameters) -# 12| 0: [Parameter] value -# 12| 4: [BlockStmt] {...} -# 12| 0: [ExprStmt] ...; -# 12| 0: [AssignExpr] ... = ... -# 12| 0: [PropertyCall] access to property Prop1 -# 12| 1: [ParameterAccess] access to parameter value -# 13| 6: [Property] Prop1 +# 5| 0: [Parameter] value +# 5| 4: [BlockStmt] {...} +# 5| 0: [ExprStmt] ...; +# 5| 0: [AssignExpr] ... = ... +# 5| 0: [PropertyCall] access to property Prop1 +# 5| 1: [ParameterAccess] access to parameter value +# 6| 6: [Property] Prop1 +# 6| -1: [TypeMention] int +# 6| 3: [Getter] get_Prop1 +# 6| 4: [Setter] set_Prop1 +#-----| 2: (Parameters) +# 6| 0: [Parameter] value +# 7| 7: [Property] Prop2 +# 7| -1: [TypeMention] int +# 7| 3: [Getter] get_Prop2 +# 7| 4: [Setter] set_Prop2 +#-----| 2: (Parameters) +# 7| 0: [Parameter] value +# 11| [Class] Derived +#-----| 3: (Base types) +# 11| 0: [TypeMention] Base +# 13| 5: [Property] Prop1 # 13| -1: [TypeMention] int # 13| 3: [Getter] get_Prop1 # 13| 4: [Setter] set_Prop1 #-----| 2: (Parameters) # 13| 0: [Parameter] value -# 14| 7: [Property] Prop2 +# 14| 6: [Property] Prop2 # 14| -1: [TypeMention] int -# 14| 3: [Getter] get_Prop2 -# 14| 4: [Setter] set_Prop2 +# 16| 3: [Getter] get_Prop2 +# 16| 4: [BlockStmt] {...} +# 16| 0: [ReturnStmt] return ...; +# 16| 0: [IntLiteral] 0 +# 17| 4: [Setter] set_Prop2 #-----| 2: (Parameters) -# 14| 0: [Parameter] value -# 18| [Class] Derived -#-----| 3: (Base types) -# 18| 0: [TypeMention] Base -# 20| 5: [Property] Prop1 -# 20| -1: [TypeMention] int -# 20| 3: [Getter] get_Prop1 -# 20| 4: [Setter] set_Prop1 -#-----| 2: (Parameters) -# 20| 0: [Parameter] value -# 21| 6: [Property] Prop2 -# 21| -1: [TypeMention] int -# 23| 3: [Getter] get_Prop2 -# 23| 4: [BlockStmt] {...} -# 23| 0: [ReturnStmt] return ...; -# 23| 0: [IntLiteral] 0 -# 24| 4: [Setter] set_Prop2 -#-----| 2: (Parameters) -# 24| 0: [Parameter] value -# 25| 4: [BlockStmt] {...} -# 26| 0: [ExprStmt] ...; -# 26| 0: [MethodCall] call to method WriteLine -# 26| -1: [TypeAccess] access to type Console -# 26| 0: [TypeMention] Console -# 26| 0: [ParameterAccess] access to parameter value -# 27| 1: [ExprStmt] ...; -# 27| 0: [AssignExpr] ... = ... -# 27| 0: [PropertyCall] access to property Prop1 -# 27| 1: [ParameterAccess] access to parameter value -# 28| 2: [ExprStmt] ...; -# 28| 0: [AssignExpr] ... = ... -# 28| 0: [PropertyCall] access to property Prop0 -# 28| 1: [ParameterAccess] access to parameter value -# 33| [Class] C1 -# 35| 5: [Method] M1 -# 35| -1: [TypeMention] Void -# 36| 4: [BlockStmt] {...} -# 37| 0: [LocalVariableDeclStmt] ... ...; -# 37| 0: [LocalVariableDeclAndInitExpr] Derived d = ... -# 37| -1: [TypeMention] Derived -# 37| 0: [LocalVariableAccess] access to local variable d -# 37| 1: [ObjectCreation] object creation of type Derived -# 37| -2: [TypeMention] Derived -# 38| -1: [ObjectInitializer] { ..., ... } -# 39| 0: [MemberInitializer] ... = ... -# 39| 0: [PropertyCall] access to property Prop1 -# 39| 1: [IntLiteral] 1 -# 40| 1: [MemberInitializer] ... = ... -# 40| 0: [PropertyCall] access to property Prop2 -# 40| 1: [IntLiteral] 2 -# 41| 2: [MemberInitializer] ... = ... -# 41| 0: [PropertyCall] access to property Prop0 -# 41| 1: [IntLiteral] 0 +# 17| 0: [Parameter] value +# 18| 4: [BlockStmt] {...} +# 19| 0: [ExprStmt] ...; +# 19| 0: [MethodCall] call to method WriteLine +# 19| -1: [TypeAccess] access to type Console +# 19| 0: [TypeMention] Console +# 19| 0: [ParameterAccess] access to parameter value +# 20| 1: [ExprStmt] ...; +# 20| 0: [AssignExpr] ... = ... +# 20| 0: [PropertyCall] access to property Prop1 +# 20| 1: [ParameterAccess] access to parameter value +# 21| 2: [ExprStmt] ...; +# 21| 0: [AssignExpr] ... = ... +# 21| 0: [PropertyCall] access to property Prop0 +# 21| 1: [ParameterAccess] access to parameter value +# 26| [Class] C1 +# 28| 5: [Method] M1 +# 28| -1: [TypeMention] Void +# 29| 4: [BlockStmt] {...} +# 30| 0: [LocalVariableDeclStmt] ... ...; +# 30| 0: [LocalVariableDeclAndInitExpr] Derived d = ... +# 30| -1: [TypeMention] Derived +# 30| 0: [LocalVariableAccess] access to local variable d +# 30| 1: [ObjectCreation] object creation of type Derived +# 30| -2: [TypeMention] Derived +# 31| -1: [ObjectInitializer] { ..., ... } +# 32| 0: [MemberInitializer] ... = ... +# 32| 0: [PropertyCall] access to property Prop1 +# 32| 1: [IntLiteral] 1 +# 33| 1: [MemberInitializer] ... = ... +# 33| 0: [PropertyCall] access to property Prop2 +# 33| 1: [IntLiteral] 2 +# 34| 2: [MemberInitializer] ... = ... +# 34| 0: [PropertyCall] access to property Prop0 +# 34| 1: [IntLiteral] 0 +IsExternalInit.cs: +# 4| [NamespaceDeclaration] namespace ... { ... } +# 6| 1: [Class] IsExternalInit LambdaModifier.cs: # 4| [Class] Class1 # 6| 5: [Method] M1 @@ -656,6 +657,288 @@ ParenthesizedPattern.cs: # 27| 0: [TypeAccessPatternExpr] access to type String # 27| 0: [TypeMention] string # 27| 2: [IntLiteral] 5 +Record.cs: +# 4| [Class] Person +# 4| 11: [Property] EqualityContract +# 4| 3: [Getter] get_EqualityContract +# 4| 11: [NEOperator] != +#-----| 2: (Parameters) +# 4| 0: [Parameter] r1 +# 4| 1: [Parameter] r2 +# 4| 11: [EQOperator] == +#-----| 2: (Parameters) +# 4| 0: [Parameter] r1 +# 4| 1: [Parameter] r2 +# 6| 14: [IndexerProperty] LastName +# 6| -1: [TypeMention] string +# 6| 3: [Getter] get_LastName +# 7| 15: [IndexerProperty] FirstName +# 7| -1: [TypeMention] string +# 7| 3: [Getter] get_FirstName +# 9| 16: [InstanceConstructor] Person +#-----| 2: (Parameters) +# 9| 0: [Parameter] first +# 9| -1: [TypeMention] string +# 9| 1: [Parameter] last +# 9| -1: [TypeMention] string +# 9| 4: [AssignExpr] ... = ... +# 9| 0: [TupleExpr] (..., ...) +# 9| 0: [PropertyCall] access to property FirstName +# 9| 1: [PropertyCall] access to property LastName +# 9| 1: [TupleExpr] (..., ...) +# 9| 0: [ParameterAccess] access to parameter first +# 9| 1: [ParameterAccess] access to parameter last +# 12| [Class] Teacher +# 12| 12: [Property] EqualityContract +# 12| 3: [Getter] get_EqualityContract +# 12| 12: [NEOperator] != +#-----| 2: (Parameters) +# 12| 0: [Parameter] r1 +# 12| 1: [Parameter] r2 +# 12| 12: [EQOperator] == +#-----| 2: (Parameters) +# 12| 0: [Parameter] r1 +# 12| 1: [Parameter] r2 +# 14| 15: [IndexerProperty] Subject +# 14| -1: [TypeMention] string +# 14| 3: [Getter] get_Subject +# 16| 16: [InstanceConstructor] Teacher +#-----| 2: (Parameters) +# 16| 0: [Parameter] first +# 16| -1: [TypeMention] string +# 16| 1: [Parameter] last +# 16| -1: [TypeMention] string +# 16| 2: [Parameter] sub +# 16| -1: [TypeMention] string +# 17| 3: [ConstructorInitializer] call to constructor Person +# 17| 0: [ParameterAccess] access to parameter first +# 17| 1: [ParameterAccess] access to parameter last +# 17| 4: [AssignExpr] ... = ... +# 17| 0: [PropertyCall] access to property Subject +# 17| 1: [ParameterAccess] access to parameter sub +# 20| [Class] Student +# 20| 12: [Property] EqualityContract +# 20| 3: [Getter] get_EqualityContract +# 20| 12: [NEOperator] != +#-----| 2: (Parameters) +# 20| 0: [Parameter] r1 +# 20| 1: [Parameter] r2 +# 20| 12: [EQOperator] == +#-----| 2: (Parameters) +# 20| 0: [Parameter] r1 +# 20| 1: [Parameter] r2 +# 22| 15: [Property] Level +# 22| -1: [TypeMention] int +# 22| 3: [Getter] get_Level +# 24| 16: [InstanceConstructor] Student +#-----| 2: (Parameters) +# 24| 0: [Parameter] first +# 24| -1: [TypeMention] string +# 24| 1: [Parameter] last +# 24| -1: [TypeMention] string +# 24| 2: [Parameter] level +# 24| -1: [TypeMention] int +# 24| 3: [ConstructorInitializer] call to constructor Person +# 24| 0: [ParameterAccess] access to parameter first +# 24| 1: [ParameterAccess] access to parameter last +# 24| 4: [AssignExpr] ... = ... +# 24| 0: [PropertyCall] access to property Level +# 24| 1: [ParameterAccess] access to parameter level +# 27| [Class] Person1 +# 27| 12: [Property] EqualityContract +# 27| 3: [Getter] get_EqualityContract +# 27| 12: [InstanceConstructor] Person1 +#-----| 2: (Parameters) +# 27| 0: [Parameter] FirstName +# 27| -1: [TypeMention] string +# 27| 1: [Parameter] LastName +# 27| -1: [TypeMention] string +# 27| 12: [NEOperator] != +#-----| 2: (Parameters) +# 27| 0: [Parameter] r1 +# 27| 1: [Parameter] r2 +# 27| 12: [EQOperator] == +#-----| 2: (Parameters) +# 27| 0: [Parameter] r1 +# 27| 1: [Parameter] r2 +# 27| 16: [IndexerProperty] FirstName +# 27| 3: [Getter] get_FirstName +# 27| 4: [Setter] set_FirstName +#-----| 2: (Parameters) +# 27| 0: [Parameter] value +# 27| 17: [IndexerProperty] LastName +# 27| 3: [Getter] get_LastName +# 27| 4: [Setter] set_LastName +#-----| 2: (Parameters) +# 27| 0: [Parameter] value +# 29| [Class] Teacher1 +# 29| 13: [Property] EqualityContract +# 29| 3: [Getter] get_EqualityContract +# 29| 13: [NEOperator] != +#-----| 2: (Parameters) +# 29| 0: [Parameter] r1 +# 29| 1: [Parameter] r2 +# 29| 13: [EQOperator] == +#-----| 2: (Parameters) +# 29| 0: [Parameter] r1 +# 29| 1: [Parameter] r2 +# 29| 13: [InstanceConstructor] Teacher1 +#-----| 2: (Parameters) +# 29| 0: [Parameter] FirstName +# 29| -1: [TypeMention] string +# 29| 1: [Parameter] LastName +# 29| -1: [TypeMention] string +# 29| 2: [Parameter] Subject +# 29| -1: [TypeMention] string +# 29| 17: [IndexerProperty] Subject +# 29| 3: [Getter] get_Subject +# 29| 4: [Setter] set_Subject +#-----| 2: (Parameters) +# 29| 0: [Parameter] value +# 32| [Class] Student1 +# 32| 13: [Property] EqualityContract +# 32| 3: [Getter] get_EqualityContract +# 32| 13: [NEOperator] != +#-----| 2: (Parameters) +# 32| 0: [Parameter] r1 +# 32| 1: [Parameter] r2 +# 32| 13: [EQOperator] == +#-----| 2: (Parameters) +# 32| 0: [Parameter] r1 +# 32| 1: [Parameter] r2 +# 32| 13: [InstanceConstructor] Student1 +#-----| 2: (Parameters) +# 32| 0: [Parameter] FirstName +# 32| -1: [TypeMention] string +# 32| 1: [Parameter] LastName +# 32| -1: [TypeMention] string +# 32| 2: [Parameter] Level +# 32| -1: [TypeMention] int +# 32| 17: [Property] Level +# 32| 3: [Getter] get_Level +# 32| 4: [Setter] set_Level +#-----| 2: (Parameters) +# 32| 0: [Parameter] value +# 35| [Class] Pet +# 35| 12: [Property] EqualityContract +# 35| 3: [Getter] get_EqualityContract +# 35| 12: [NEOperator] != +#-----| 2: (Parameters) +# 35| 0: [Parameter] r1 +# 35| 1: [Parameter] r2 +# 35| 12: [EQOperator] == +#-----| 2: (Parameters) +# 35| 0: [Parameter] r1 +# 35| 1: [Parameter] r2 +# 35| 12: [InstanceConstructor] Pet +#-----| 2: (Parameters) +# 35| 0: [Parameter] Name +# 35| -1: [TypeMention] string +# 35| 16: [IndexerProperty] Name +# 35| 3: [Getter] get_Name +# 35| 4: [Setter] set_Name +#-----| 2: (Parameters) +# 35| 0: [Parameter] value +# 37| 17: [Method] ShredTheFurniture +# 37| -1: [TypeMention] Void +# 38| 4: [MethodCall] call to method WriteLine +# 38| -1: [TypeAccess] access to type Console +# 38| 0: [TypeMention] Console +# 38| 0: [StringLiteral] "Shredding furniture" +# 41| [Class] Dog +# 41| 12: [Property] EqualityContract +# 41| 3: [Getter] get_EqualityContract +# 41| 12: [NEOperator] != +#-----| 2: (Parameters) +# 41| 0: [Parameter] r1 +# 41| 1: [Parameter] r2 +# 41| 12: [EQOperator] == +#-----| 2: (Parameters) +# 41| 0: [Parameter] r1 +# 41| 1: [Parameter] r2 +# 41| 12: [InstanceConstructor] Dog +#-----| 2: (Parameters) +# 41| 0: [Parameter] Name +# 41| -1: [TypeMention] string +# 43| 16: [Method] WagTail +# 43| -1: [TypeMention] Void +# 44| 4: [MethodCall] call to method WriteLine +# 44| -1: [TypeAccess] access to type Console +# 44| 0: [TypeMention] Console +# 44| 0: [StringLiteral] "It's tail wagging time" +# 46| 17: [Method] ToString +# 46| -1: [TypeMention] string +# 47| 4: [BlockStmt] {...} +# 48| 0: [LocalVariableDeclStmt] ... ...; +# 48| 0: [LocalVariableDeclAndInitExpr] StringBuilder s = ... +# 48| -1: [TypeMention] StringBuilder +# 48| 0: [LocalVariableAccess] access to local variable s +# 48| 1: [ObjectCreation] object creation of type StringBuilder +# 48| 0: [TypeMention] StringBuilder +# 49| 1: [ExprStmt] ...; +# 49| 0: [MethodCall] call to method PrintMembers +# 49| -1: [BaseAccess] base access +# 49| 0: [LocalVariableAccess] access to local variable s +# 50| 2: [ReturnStmt] return ...; +# 50| 0: [InterpolatedStringExpr] $"..." +# 50| 0: [MethodCall] call to method ToString +# 50| -1: [LocalVariableAccess] access to local variable s +# 50| 1: [StringLiteral] " is a dog" +# 54| [Class] Record1 +# 56| 5: [Method] M1 +# 56| -1: [TypeMention] Void +# 57| 4: [BlockStmt] {...} +# 58| 0: [LocalVariableDeclStmt] ... ...; +# 58| 0: [LocalVariableDeclAndInitExpr] Person person = ... +# 58| -1: [TypeMention] Person +# 58| 0: [LocalVariableAccess] access to local variable person +# 58| 1: [ObjectCreation] object creation of type Person +# 58| -1: [TypeMention] Person +# 58| 0: [StringLiteral] "Bill" +# 58| 1: [StringLiteral] "Wagner" +# 59| 1: [LocalVariableDeclStmt] ... ...; +# 59| 0: [LocalVariableDeclAndInitExpr] Student student = ... +# 59| -1: [TypeMention] Student +# 59| 0: [LocalVariableAccess] access to local variable student +# 59| 1: [ObjectCreation] object creation of type Student +# 59| -1: [TypeMention] Student +# 59| 0: [StringLiteral] "Bill" +# 59| 1: [StringLiteral] "Wagner" +# 59| 2: [IntLiteral] 11 +# 61| 2: [ExprStmt] ...; +# 61| 0: [MethodCall] call to method WriteLine +# 61| -1: [TypeAccess] access to type Console +# 61| 0: [TypeMention] Console +# 61| 0: [OperatorCall] call to operator == +# 61| 0: [LocalVariableAccess] access to local variable student +# 61| 1: [LocalVariableAccess] access to local variable person +# 64| 6: [Method] M2 +# 64| -1: [TypeMention] Void +# 65| 4: [BlockStmt] {...} +# 66| 0: [LocalVariableDeclStmt] ... ...; +# 66| 0: [LocalVariableDeclAndInitExpr] Person1 person = ... +# 66| -1: [TypeMention] Person1 +# 66| 0: [LocalVariableAccess] access to local variable person +# 66| 1: [ObjectCreation] object creation of type Person1 +# 66| -1: [TypeMention] Person1 +# 66| 0: [StringLiteral] "Bill" +# 66| 1: [StringLiteral] "Wagner" +# 68| 1: [ExprStmt] ...; +# 68| 0: [AssignExpr] ... = ... +# 68| 0: [TupleExpr] (..., ...) +# 68| 0: [LocalVariableDeclExpr] String first +# 68| 1: [LocalVariableDeclExpr] String last +# 68| 1: [LocalVariableAccess] access to local variable person +# 69| 2: [ExprStmt] ...; +# 69| 0: [MethodCall] call to method WriteLine +# 69| -1: [TypeAccess] access to type Console +# 69| 0: [TypeMention] Console +# 69| 0: [LocalVariableAccess] access to local variable first +# 70| 3: [ExprStmt] ...; +# 70| 0: [MethodCall] call to method WriteLine +# 70| -1: [TypeAccess] access to type Console +# 70| 0: [TypeMention] Console +# 70| 0: [LocalVariableAccess] access to local variable last RelationalPattern.cs: # 3| [Class] RelationalPattern # 5| 5: [Method] M1 diff --git a/csharp/ql/test/library-tests/csharp9/Record.cs b/csharp/ql/test/library-tests/csharp9/Record.cs new file mode 100644 index 00000000000..45d1506c055 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/Record.cs @@ -0,0 +1,72 @@ +using System; +using System.Text; + +public record Person +{ + public string LastName { get; } + public string FirstName { get; } + + public Person(string first, string last) => (FirstName, LastName) = (first, last); +} + +public record Teacher : Person +{ + public string Subject { get; } + + public Teacher(string first, string last, string sub) + : base(first, last) => Subject = sub; +} + +public sealed record Student : Person +{ + public int Level { get; } + + public Student(string first, string last, int level) : base(first, last) => Level = level; +} + +public record Person1(string FirstName, string LastName); + +public record Teacher1(string FirstName, string LastName, string Subject) + : Person1(FirstName, LastName); + +public sealed record Student1(string FirstName, string LastName, int Level) + : Person1(FirstName, LastName); + +public record Pet(string Name) +{ + public void ShredTheFurniture() => + Console.WriteLine("Shredding furniture"); +} + +public record Dog(string Name) : Pet(Name) +{ + public void WagTail() => + Console.WriteLine("It's tail wagging time"); + + public override string ToString() + { + var s = new StringBuilder(); + base.PrintMembers(s); + return $"{s.ToString()} is a dog"; + } +} + +public class Record1 +{ + public void M1() + { + var person = new Person("Bill", "Wagner"); + var student = new Student("Bill", "Wagner", 11); + + Console.WriteLine(student == person); + } + + public void M2() + { + var person = new Person1("Bill", "Wagner"); + + var (first, last) = person; + Console.WriteLine(first); + Console.WriteLine(last); + } +} diff --git a/csharp/ql/test/library-tests/csharp9/initOnlyProperty.expected b/csharp/ql/test/library-tests/csharp9/initOnlyProperty.expected index eaa1dd96db1..ca27ad80532 100644 --- a/csharp/ql/test/library-tests/csharp9/initOnlyProperty.expected +++ b/csharp/ql/test/library-tests/csharp9/initOnlyProperty.expected @@ -1,8 +1,13 @@ | AnonymousObjectCreation.cs:9:29:9:31 | set_Prop1 | set | | BinaryPattern.cs:5:26:5:28 | set_P1 | set | -| InitOnlyProperty.cs:12:42:12:45 | set_Prop0 | init | -| InitOnlyProperty.cs:13:37:13:40 | set_Prop1 | init | -| InitOnlyProperty.cs:14:37:14:39 | set_Prop2 | set | -| InitOnlyProperty.cs:20:38:20:41 | set_Prop1 | init | -| InitOnlyProperty.cs:24:9:24:12 | set_Prop2 | init | +| InitOnlyProperty.cs:5:42:5:45 | set_Prop0 | init | +| InitOnlyProperty.cs:6:37:6:40 | set_Prop1 | init | +| InitOnlyProperty.cs:7:37:7:39 | set_Prop2 | set | +| InitOnlyProperty.cs:13:38:13:41 | set_Prop1 | init | +| InitOnlyProperty.cs:17:9:17:12 | set_Prop2 | init | +| Record.cs:27:30:27:38 | set_FirstName | init | +| Record.cs:27:48:27:55 | set_LastName | init | +| Record.cs:29:66:29:72 | set_Subject | init | +| Record.cs:32:70:32:74 | set_Level | init | +| Record.cs:35:26:35:29 | set_Name | init | | UnaryPattern.cs:5:26:5:28 | set_P1 | set | diff --git a/csharp/ql/test/library-tests/csharp9/record.expected b/csharp/ql/test/library-tests/csharp9/record.expected new file mode 100644 index 00000000000..d2a427d6554 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/record.expected @@ -0,0 +1,212 @@ +types +| Record.cs:4:1:10:1 | Person | IEquatable | +| Record.cs:12:1:18:1 | Teacher | IEquatable | +| Record.cs:20:1:25:1 | Student | IEquatable | +| Record.cs:27:1:27:57 | Person1 | IEquatable | +| Record.cs:29:1:30:35 | Teacher1 | IEquatable | +| Record.cs:32:1:33:35 | Student1 | IEquatable | +| Record.cs:35:1:39:1 | Pet | IEquatable | +| Record.cs:41:1:52:1 | Dog | IEquatable | +members +| Record.cs:4:1:10:1 | Person | Person.!=(Person, Person) | Record.cs:4:15:4:20 | +| Record.cs:4:1:10:1 | Person | Person.$() | no location | +| Record.cs:4:1:10:1 | Person | Person.==(Person, Person) | Record.cs:4:15:4:20 | +| Record.cs:4:1:10:1 | Person | Person.EqualityContract | Record.cs:4:15:4:20 | +| Record.cs:4:1:10:1 | Person | Person.Equals(Person) | no location | +| Record.cs:4:1:10:1 | Person | Person.Equals(object) | no location | +| Record.cs:4:1:10:1 | Person | Person.FirstName | Record.cs:7:19:7:27 | +| Record.cs:4:1:10:1 | Person | Person.GetHashCode() | no location | +| Record.cs:4:1:10:1 | Person | Person.LastName | Record.cs:6:19:6:26 | +| Record.cs:4:1:10:1 | Person | Person.Person(Person) | no location | +| Record.cs:4:1:10:1 | Person | Person.Person(string, string) | Record.cs:9:12:9:17 | +| Record.cs:4:1:10:1 | Person | Person.PrintMembers(StringBuilder) | no location | +| Record.cs:4:1:10:1 | Person | Person.ToString() | no location | +| Record.cs:4:1:10:1 | Person | System.Object.Equals(object, object) | no location | +| Record.cs:4:1:10:1 | Person | System.Object.GetType() | no location | +| Record.cs:4:1:10:1 | Person | System.Object.MemberwiseClone() | no location | +| Record.cs:4:1:10:1 | Person | System.Object.Object() | no location | +| Record.cs:4:1:10:1 | Person | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:4:1:10:1 | Person | System.Object.~Object() | no location | +| Record.cs:12:1:18:1 | Teacher | Person.!=(Person, Person) | Record.cs:4:15:4:20 | +| Record.cs:12:1:18:1 | Teacher | Person.==(Person, Person) | Record.cs:4:15:4:20 | +| Record.cs:12:1:18:1 | Teacher | Person.FirstName | Record.cs:7:19:7:27 | +| Record.cs:12:1:18:1 | Teacher | Person.LastName | Record.cs:6:19:6:26 | +| Record.cs:12:1:18:1 | Teacher | Person.Person(Person) | no location | +| Record.cs:12:1:18:1 | Teacher | Person.Person(string, string) | Record.cs:9:12:9:17 | +| Record.cs:12:1:18:1 | Teacher | System.Object.Equals(object, object) | no location | +| Record.cs:12:1:18:1 | Teacher | System.Object.GetType() | no location | +| Record.cs:12:1:18:1 | Teacher | System.Object.MemberwiseClone() | no location | +| Record.cs:12:1:18:1 | Teacher | System.Object.Object() | no location | +| Record.cs:12:1:18:1 | Teacher | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:12:1:18:1 | Teacher | System.Object.~Object() | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.!=(Teacher, Teacher) | Record.cs:12:15:12:21 | +| Record.cs:12:1:18:1 | Teacher | Teacher.$() | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.==(Teacher, Teacher) | Record.cs:12:15:12:21 | +| Record.cs:12:1:18:1 | Teacher | Teacher.EqualityContract | Record.cs:12:15:12:21 | +| Record.cs:12:1:18:1 | Teacher | Teacher.Equals(Person) | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.Equals(Teacher) | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.Equals(object) | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.GetHashCode() | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.PrintMembers(StringBuilder) | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.Subject | Record.cs:14:19:14:25 | +| Record.cs:12:1:18:1 | Teacher | Teacher.Teacher(Teacher) | no location | +| Record.cs:12:1:18:1 | Teacher | Teacher.Teacher(string, string, string) | Record.cs:16:12:16:18 | +| Record.cs:12:1:18:1 | Teacher | Teacher.ToString() | no location | +| Record.cs:20:1:25:1 | Student | Person.!=(Person, Person) | Record.cs:4:15:4:20 | +| Record.cs:20:1:25:1 | Student | Person.==(Person, Person) | Record.cs:4:15:4:20 | +| Record.cs:20:1:25:1 | Student | Person.FirstName | Record.cs:7:19:7:27 | +| Record.cs:20:1:25:1 | Student | Person.LastName | Record.cs:6:19:6:26 | +| Record.cs:20:1:25:1 | Student | Person.Person(Person) | no location | +| Record.cs:20:1:25:1 | Student | Person.Person(string, string) | Record.cs:9:12:9:17 | +| Record.cs:20:1:25:1 | Student | Student.!=(Student, Student) | Record.cs:20:22:20:28 | +| Record.cs:20:1:25:1 | Student | Student.$() | no location | +| Record.cs:20:1:25:1 | Student | Student.==(Student, Student) | Record.cs:20:22:20:28 | +| Record.cs:20:1:25:1 | Student | Student.EqualityContract | Record.cs:20:22:20:28 | +| Record.cs:20:1:25:1 | Student | Student.Equals(Person) | no location | +| Record.cs:20:1:25:1 | Student | Student.Equals(Student) | no location | +| Record.cs:20:1:25:1 | Student | Student.Equals(object) | no location | +| Record.cs:20:1:25:1 | Student | Student.GetHashCode() | no location | +| Record.cs:20:1:25:1 | Student | Student.Level | Record.cs:22:16:22:20 | +| Record.cs:20:1:25:1 | Student | Student.PrintMembers(StringBuilder) | no location | +| Record.cs:20:1:25:1 | Student | Student.Student(Student) | no location | +| Record.cs:20:1:25:1 | Student | Student.Student(string, string, int) | Record.cs:24:12:24:18 | +| Record.cs:20:1:25:1 | Student | Student.ToString() | no location | +| Record.cs:20:1:25:1 | Student | System.Object.Equals(object, object) | no location | +| Record.cs:20:1:25:1 | Student | System.Object.GetType() | no location | +| Record.cs:20:1:25:1 | Student | System.Object.MemberwiseClone() | no location | +| Record.cs:20:1:25:1 | Student | System.Object.Object() | no location | +| Record.cs:20:1:25:1 | Student | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:20:1:25:1 | Student | System.Object.~Object() | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.!=(Person1, Person1) | Record.cs:27:15:27:21 | +| Record.cs:27:1:27:57 | Person1 | Person1.$() | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.==(Person1, Person1) | Record.cs:27:15:27:21 | +| Record.cs:27:1:27:57 | Person1 | Person1.Deconstruct(out string, out string) | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.EqualityContract | Record.cs:27:15:27:21 | +| Record.cs:27:1:27:57 | Person1 | Person1.Equals(Person1) | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.Equals(object) | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.FirstName | Record.cs:27:30:27:38 | +| Record.cs:27:1:27:57 | Person1 | Person1.GetHashCode() | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.LastName | Record.cs:27:48:27:55 | +| Record.cs:27:1:27:57 | Person1 | Person1.Person1(Person1) | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.Person1(string, string) | Record.cs:27:15:27:21 | +| Record.cs:27:1:27:57 | Person1 | Person1.PrintMembers(StringBuilder) | no location | +| Record.cs:27:1:27:57 | Person1 | Person1.ToString() | no location | +| Record.cs:27:1:27:57 | Person1 | System.Object.Equals(object, object) | no location | +| Record.cs:27:1:27:57 | Person1 | System.Object.GetType() | no location | +| Record.cs:27:1:27:57 | Person1 | System.Object.MemberwiseClone() | no location | +| Record.cs:27:1:27:57 | Person1 | System.Object.Object() | no location | +| Record.cs:27:1:27:57 | Person1 | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:27:1:27:57 | Person1 | System.Object.~Object() | no location | +| Record.cs:29:1:30:35 | Teacher1 | Person1.!=(Person1, Person1) | Record.cs:27:15:27:21 | +| Record.cs:29:1:30:35 | Teacher1 | Person1.==(Person1, Person1) | Record.cs:27:15:27:21 | +| Record.cs:29:1:30:35 | Teacher1 | Person1.Deconstruct(out string, out string) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Person1.FirstName | Record.cs:27:30:27:38 | +| Record.cs:29:1:30:35 | Teacher1 | Person1.LastName | Record.cs:27:48:27:55 | +| Record.cs:29:1:30:35 | Teacher1 | Person1.Person1(Person1) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Person1.Person1(string, string) | Record.cs:27:15:27:21 | +| Record.cs:29:1:30:35 | Teacher1 | System.Object.Equals(object, object) | no location | +| Record.cs:29:1:30:35 | Teacher1 | System.Object.GetType() | no location | +| Record.cs:29:1:30:35 | Teacher1 | System.Object.MemberwiseClone() | no location | +| Record.cs:29:1:30:35 | Teacher1 | System.Object.Object() | no location | +| Record.cs:29:1:30:35 | Teacher1 | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:29:1:30:35 | Teacher1 | System.Object.~Object() | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.!=(Teacher1, Teacher1) | Record.cs:29:15:29:22 | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.$() | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.==(Teacher1, Teacher1) | Record.cs:29:15:29:22 | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Deconstruct(out string, out string, out string) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.EqualityContract | Record.cs:29:15:29:22 | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Equals(Person1) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Equals(Teacher1) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Equals(object) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.GetHashCode() | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.PrintMembers(StringBuilder) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Subject | Record.cs:29:66:29:72 | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Teacher1(Teacher1) | no location | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.Teacher1(string, string, string) | Record.cs:29:15:29:22 | +| Record.cs:29:1:30:35 | Teacher1 | Teacher1.ToString() | no location | +| Record.cs:32:1:33:35 | Student1 | Person1.!=(Person1, Person1) | Record.cs:27:15:27:21 | +| Record.cs:32:1:33:35 | Student1 | Person1.==(Person1, Person1) | Record.cs:27:15:27:21 | +| Record.cs:32:1:33:35 | Student1 | Person1.Deconstruct(out string, out string) | no location | +| Record.cs:32:1:33:35 | Student1 | Person1.FirstName | Record.cs:27:30:27:38 | +| Record.cs:32:1:33:35 | Student1 | Person1.LastName | Record.cs:27:48:27:55 | +| Record.cs:32:1:33:35 | Student1 | Person1.Person1(Person1) | no location | +| Record.cs:32:1:33:35 | Student1 | Person1.Person1(string, string) | Record.cs:27:15:27:21 | +| Record.cs:32:1:33:35 | Student1 | Student1.!=(Student1, Student1) | Record.cs:32:22:32:29 | +| Record.cs:32:1:33:35 | Student1 | Student1.$() | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.==(Student1, Student1) | Record.cs:32:22:32:29 | +| Record.cs:32:1:33:35 | Student1 | Student1.Deconstruct(out string, out string, out int) | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.EqualityContract | Record.cs:32:22:32:29 | +| Record.cs:32:1:33:35 | Student1 | Student1.Equals(Person1) | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.Equals(Student1) | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.Equals(object) | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.GetHashCode() | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.Level | Record.cs:32:70:32:74 | +| Record.cs:32:1:33:35 | Student1 | Student1.PrintMembers(StringBuilder) | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.Student1(Student1) | no location | +| Record.cs:32:1:33:35 | Student1 | Student1.Student1(string, string, int) | Record.cs:32:22:32:29 | +| Record.cs:32:1:33:35 | Student1 | Student1.ToString() | no location | +| Record.cs:32:1:33:35 | Student1 | System.Object.Equals(object, object) | no location | +| Record.cs:32:1:33:35 | Student1 | System.Object.GetType() | no location | +| Record.cs:32:1:33:35 | Student1 | System.Object.MemberwiseClone() | no location | +| Record.cs:32:1:33:35 | Student1 | System.Object.Object() | no location | +| Record.cs:32:1:33:35 | Student1 | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:32:1:33:35 | Student1 | System.Object.~Object() | no location | +| Record.cs:35:1:39:1 | Pet | Pet.!=(Pet, Pet) | Record.cs:35:15:35:17 | +| Record.cs:35:1:39:1 | Pet | Pet.$() | no location | +| Record.cs:35:1:39:1 | Pet | Pet.==(Pet, Pet) | Record.cs:35:15:35:17 | +| Record.cs:35:1:39:1 | Pet | Pet.Deconstruct(out string) | no location | +| Record.cs:35:1:39:1 | Pet | Pet.EqualityContract | Record.cs:35:15:35:17 | +| Record.cs:35:1:39:1 | Pet | Pet.Equals(Pet) | no location | +| Record.cs:35:1:39:1 | Pet | Pet.Equals(object) | no location | +| Record.cs:35:1:39:1 | Pet | Pet.GetHashCode() | no location | +| Record.cs:35:1:39:1 | Pet | Pet.Name | Record.cs:35:26:35:29 | +| Record.cs:35:1:39:1 | Pet | Pet.Pet(Pet) | no location | +| Record.cs:35:1:39:1 | Pet | Pet.Pet(string) | Record.cs:35:15:35:17 | +| Record.cs:35:1:39:1 | Pet | Pet.PrintMembers(StringBuilder) | no location | +| Record.cs:35:1:39:1 | Pet | Pet.ShredTheFurniture() | Record.cs:37:17:37:33 | +| Record.cs:35:1:39:1 | Pet | Pet.ToString() | no location | +| Record.cs:35:1:39:1 | Pet | System.Object.Equals(object, object) | no location | +| Record.cs:35:1:39:1 | Pet | System.Object.GetType() | no location | +| Record.cs:35:1:39:1 | Pet | System.Object.MemberwiseClone() | no location | +| Record.cs:35:1:39:1 | Pet | System.Object.Object() | no location | +| Record.cs:35:1:39:1 | Pet | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:35:1:39:1 | Pet | System.Object.~Object() | no location | +| Record.cs:41:1:52:1 | Dog | Dog.!=(Dog, Dog) | Record.cs:41:15:41:17 | +| Record.cs:41:1:52:1 | Dog | Dog.$() | no location | +| Record.cs:41:1:52:1 | Dog | Dog.==(Dog, Dog) | Record.cs:41:15:41:17 | +| Record.cs:41:1:52:1 | Dog | Dog.Deconstruct(out string) | no location | +| Record.cs:41:1:52:1 | Dog | Dog.Dog(Dog) | no location | +| Record.cs:41:1:52:1 | Dog | Dog.Dog(string) | Record.cs:41:15:41:17 | +| Record.cs:41:1:52:1 | Dog | Dog.EqualityContract | Record.cs:41:15:41:17 | +| Record.cs:41:1:52:1 | Dog | Dog.Equals(Dog) | no location | +| Record.cs:41:1:52:1 | Dog | Dog.Equals(Pet) | no location | +| Record.cs:41:1:52:1 | Dog | Dog.Equals(object) | no location | +| Record.cs:41:1:52:1 | Dog | Dog.GetHashCode() | no location | +| Record.cs:41:1:52:1 | Dog | Dog.PrintMembers(StringBuilder) | no location | +| Record.cs:41:1:52:1 | Dog | Dog.ToString() | Record.cs:46:28:46:35 | +| Record.cs:41:1:52:1 | Dog | Dog.WagTail() | Record.cs:43:17:43:23 | +| Record.cs:41:1:52:1 | Dog | Pet.!=(Pet, Pet) | Record.cs:35:15:35:17 | +| Record.cs:41:1:52:1 | Dog | Pet.==(Pet, Pet) | Record.cs:35:15:35:17 | +| Record.cs:41:1:52:1 | Dog | Pet.Deconstruct(out string) | no location | +| Record.cs:41:1:52:1 | Dog | Pet.Name | Record.cs:35:26:35:29 | +| Record.cs:41:1:52:1 | Dog | Pet.Pet(Pet) | no location | +| Record.cs:41:1:52:1 | Dog | Pet.Pet(string) | Record.cs:35:15:35:17 | +| Record.cs:41:1:52:1 | Dog | Pet.ShredTheFurniture() | Record.cs:37:17:37:33 | +| Record.cs:41:1:52:1 | Dog | System.Object.Equals(object, object) | no location | +| Record.cs:41:1:52:1 | Dog | System.Object.GetType() | no location | +| Record.cs:41:1:52:1 | Dog | System.Object.MemberwiseClone() | no location | +| Record.cs:41:1:52:1 | Dog | System.Object.Object() | no location | +| Record.cs:41:1:52:1 | Dog | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:41:1:52:1 | Dog | System.Object.~Object() | no location | +| Record.cs:54:14:54:20 | Record1 | Record1.M1() | Record.cs:56:17:56:18 | +| Record.cs:54:14:54:20 | Record1 | Record1.M2() | Record.cs:64:17:64:18 | +| Record.cs:54:14:54:20 | Record1 | Record1.Record1() | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.Equals(object) | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.Equals(object, object) | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.GetHashCode() | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.GetType() | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.MemberwiseClone() | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.Object() | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.ReferenceEquals(object, object) | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.ToString() | no location | +| Record.cs:54:14:54:20 | Record1 | System.Object.~Object() | no location | diff --git a/csharp/ql/test/library-tests/csharp9/record.ql b/csharp/ql/test/library-tests/csharp9/record.ql new file mode 100644 index 00000000000..5dce739deda --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/record.ql @@ -0,0 +1,18 @@ +import csharp + +query predicate types(Class t, string i) { + t.getFile().getStem() = "Record" and + t.getABaseInterface().toStringWithTypes() = i +} + +private string getMemberName(Member m) { + result = m.getDeclaringType().getQualifiedName() + "." + m.toStringWithTypes() +} + +query predicate members(Class t, string ms, string l) { + t.getFile().getStem() = "Record" and + exists(Member m | t.hasMember(m) | + ms = getMemberName(m) and + if m.fromSource() then l = m.getLocation().toString() else l = "no location" + ) +} From 9ffc38f5b1fc6abdbf75a9e3e85156e7942dad62 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 25 Jan 2021 11:56:25 +0100 Subject: [PATCH 194/429] Fix deterministic ordering of class members in PrintAst --- csharp/ql/src/semmle/code/csharp/PrintAst.qll | 5 +- .../library-tests/csharp9/PrintAst.expected | 70 +++++++++---------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/PrintAst.qll b/csharp/ql/src/semmle/code/csharp/PrintAst.qll index f623860ff2d..024dfc2a05e 100644 --- a/csharp/ql/src/semmle/code/csharp/PrintAst.qll +++ b/csharp/ql/src/semmle/code/csharp/PrintAst.qll @@ -571,11 +571,12 @@ final class TypeNode extends ElementNode { result.(BaseTypesNode).getValueOrRefType() = type or result.(ElementNode).getElement() = - rank[childIndex - 3](Member m, string file, int line, int column | + rank[childIndex - 3](Member m, string file, int line, int column, string name | m = type.getAMember() and + name = m.getName() and locationSortKeys(m, file, line, column) | - m order by file, line, column + m order by file, line, column, name ) } } diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index 4d4288d3649..3ef4be8b9ce 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -659,16 +659,16 @@ ParenthesizedPattern.cs: # 27| 2: [IntLiteral] 5 Record.cs: # 4| [Class] Person -# 4| 11: [Property] EqualityContract -# 4| 3: [Getter] get_EqualityContract # 4| 11: [NEOperator] != #-----| 2: (Parameters) # 4| 0: [Parameter] r1 # 4| 1: [Parameter] r2 -# 4| 11: [EQOperator] == +# 4| 12: [EQOperator] == #-----| 2: (Parameters) # 4| 0: [Parameter] r1 # 4| 1: [Parameter] r2 +# 4| 13: [Property] EqualityContract +# 4| 3: [Getter] get_EqualityContract # 6| 14: [IndexerProperty] LastName # 6| -1: [TypeMention] string # 6| 3: [Getter] get_LastName @@ -689,16 +689,16 @@ Record.cs: # 9| 0: [ParameterAccess] access to parameter first # 9| 1: [ParameterAccess] access to parameter last # 12| [Class] Teacher -# 12| 12: [Property] EqualityContract -# 12| 3: [Getter] get_EqualityContract # 12| 12: [NEOperator] != #-----| 2: (Parameters) # 12| 0: [Parameter] r1 # 12| 1: [Parameter] r2 -# 12| 12: [EQOperator] == +# 12| 13: [EQOperator] == #-----| 2: (Parameters) # 12| 0: [Parameter] r1 # 12| 1: [Parameter] r2 +# 12| 14: [Property] EqualityContract +# 12| 3: [Getter] get_EqualityContract # 14| 15: [IndexerProperty] Subject # 14| -1: [TypeMention] string # 14| 3: [Getter] get_Subject @@ -717,16 +717,16 @@ Record.cs: # 17| 0: [PropertyCall] access to property Subject # 17| 1: [ParameterAccess] access to parameter sub # 20| [Class] Student -# 20| 12: [Property] EqualityContract -# 20| 3: [Getter] get_EqualityContract # 20| 12: [NEOperator] != #-----| 2: (Parameters) # 20| 0: [Parameter] r1 # 20| 1: [Parameter] r2 -# 20| 12: [EQOperator] == +# 20| 13: [EQOperator] == #-----| 2: (Parameters) # 20| 0: [Parameter] r1 # 20| 1: [Parameter] r2 +# 20| 14: [Property] EqualityContract +# 20| 3: [Getter] get_EqualityContract # 22| 15: [Property] Level # 22| -1: [TypeMention] int # 22| 3: [Getter] get_Level @@ -745,22 +745,22 @@ Record.cs: # 24| 0: [PropertyCall] access to property Level # 24| 1: [ParameterAccess] access to parameter level # 27| [Class] Person1 -# 27| 12: [Property] EqualityContract +# 27| 12: [NEOperator] != +#-----| 2: (Parameters) +# 27| 0: [Parameter] r1 +# 27| 1: [Parameter] r2 +# 27| 13: [EQOperator] == +#-----| 2: (Parameters) +# 27| 0: [Parameter] r1 +# 27| 1: [Parameter] r2 +# 27| 14: [Property] EqualityContract # 27| 3: [Getter] get_EqualityContract -# 27| 12: [InstanceConstructor] Person1 +# 27| 15: [InstanceConstructor] Person1 #-----| 2: (Parameters) # 27| 0: [Parameter] FirstName # 27| -1: [TypeMention] string # 27| 1: [Parameter] LastName # 27| -1: [TypeMention] string -# 27| 12: [NEOperator] != -#-----| 2: (Parameters) -# 27| 0: [Parameter] r1 -# 27| 1: [Parameter] r2 -# 27| 12: [EQOperator] == -#-----| 2: (Parameters) -# 27| 0: [Parameter] r1 -# 27| 1: [Parameter] r2 # 27| 16: [IndexerProperty] FirstName # 27| 3: [Getter] get_FirstName # 27| 4: [Setter] set_FirstName @@ -772,17 +772,17 @@ Record.cs: #-----| 2: (Parameters) # 27| 0: [Parameter] value # 29| [Class] Teacher1 -# 29| 13: [Property] EqualityContract -# 29| 3: [Getter] get_EqualityContract # 29| 13: [NEOperator] != #-----| 2: (Parameters) # 29| 0: [Parameter] r1 # 29| 1: [Parameter] r2 -# 29| 13: [EQOperator] == +# 29| 14: [EQOperator] == #-----| 2: (Parameters) # 29| 0: [Parameter] r1 # 29| 1: [Parameter] r2 -# 29| 13: [InstanceConstructor] Teacher1 +# 29| 15: [Property] EqualityContract +# 29| 3: [Getter] get_EqualityContract +# 29| 16: [InstanceConstructor] Teacher1 #-----| 2: (Parameters) # 29| 0: [Parameter] FirstName # 29| -1: [TypeMention] string @@ -796,17 +796,17 @@ Record.cs: #-----| 2: (Parameters) # 29| 0: [Parameter] value # 32| [Class] Student1 -# 32| 13: [Property] EqualityContract -# 32| 3: [Getter] get_EqualityContract # 32| 13: [NEOperator] != #-----| 2: (Parameters) # 32| 0: [Parameter] r1 # 32| 1: [Parameter] r2 -# 32| 13: [EQOperator] == +# 32| 14: [EQOperator] == #-----| 2: (Parameters) # 32| 0: [Parameter] r1 # 32| 1: [Parameter] r2 -# 32| 13: [InstanceConstructor] Student1 +# 32| 15: [Property] EqualityContract +# 32| 3: [Getter] get_EqualityContract +# 32| 16: [InstanceConstructor] Student1 #-----| 2: (Parameters) # 32| 0: [Parameter] FirstName # 32| -1: [TypeMention] string @@ -820,17 +820,17 @@ Record.cs: #-----| 2: (Parameters) # 32| 0: [Parameter] value # 35| [Class] Pet -# 35| 12: [Property] EqualityContract -# 35| 3: [Getter] get_EqualityContract # 35| 12: [NEOperator] != #-----| 2: (Parameters) # 35| 0: [Parameter] r1 # 35| 1: [Parameter] r2 -# 35| 12: [EQOperator] == +# 35| 13: [EQOperator] == #-----| 2: (Parameters) # 35| 0: [Parameter] r1 # 35| 1: [Parameter] r2 -# 35| 12: [InstanceConstructor] Pet +# 35| 14: [Property] EqualityContract +# 35| 3: [Getter] get_EqualityContract +# 35| 15: [InstanceConstructor] Pet #-----| 2: (Parameters) # 35| 0: [Parameter] Name # 35| -1: [TypeMention] string @@ -846,20 +846,20 @@ Record.cs: # 38| 0: [TypeMention] Console # 38| 0: [StringLiteral] "Shredding furniture" # 41| [Class] Dog -# 41| 12: [Property] EqualityContract -# 41| 3: [Getter] get_EqualityContract # 41| 12: [NEOperator] != #-----| 2: (Parameters) # 41| 0: [Parameter] r1 # 41| 1: [Parameter] r2 -# 41| 12: [EQOperator] == +# 41| 13: [EQOperator] == #-----| 2: (Parameters) # 41| 0: [Parameter] r1 # 41| 1: [Parameter] r2 -# 41| 12: [InstanceConstructor] Dog +# 41| 14: [InstanceConstructor] Dog #-----| 2: (Parameters) # 41| 0: [Parameter] Name # 41| -1: [TypeMention] string +# 41| 15: [Property] EqualityContract +# 41| 3: [Getter] get_EqualityContract # 43| 16: [Method] WagTail # 43| -1: [TypeMention] Void # 44| 4: [MethodCall] call to method WriteLine From f0b0845f9fe7a910556c454c683b47d70ccea6f8 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 1 Feb 2021 16:29:37 +0100 Subject: [PATCH 195/429] Add 'record' QL class --- csharp/ql/src/semmle/code/cil/Declaration.qll | 23 +++++++------------ csharp/ql/src/semmle/code/cil/Types.qll | 5 ++++ csharp/ql/src/semmle/code/csharp/Member.qll | 14 +++++++++++ csharp/ql/src/semmle/code/csharp/Type.qll | 15 ++++++++++++ .../ql/src/semmle/code/dotnet/Declaration.qll | 23 ++++++++++++++++++- csharp/ql/src/semmle/code/dotnet/Type.qll | 12 ++++++++++ .../library-tests/csharp9/PrintAst.expected | 16 ++++++------- .../library-tests/csharp9/record.expected | 12 ---------- .../ql/test/library-tests/csharp9/record.ql | 8 ++----- 9 files changed, 86 insertions(+), 42 deletions(-) diff --git a/csharp/ql/src/semmle/code/cil/Declaration.qll b/csharp/ql/src/semmle/code/cil/Declaration.qll index 0c58d55caef..a747d4a6d80 100644 --- a/csharp/ql/src/semmle/code/cil/Declaration.qll +++ b/csharp/ql/src/semmle/code/cil/Declaration.qll @@ -51,30 +51,23 @@ private predicate toCSharpTypeParameterJoin(TypeParameter tp, int i, CS::Unbound * A member of a type. Either a type (`Type`), a method (`Method`), a property (`Property`), or an event (`Event`). */ class Member extends DotNet::Member, Declaration, @cil_member { - /** Holds if this member is declared `public`. */ - predicate isPublic() { cil_public(this) } + override predicate isPublic() { cil_public(this) } - /** Holds if this member is declared `protected.` */ - predicate isProtected() { cil_protected(this) } + override predicate isProtected() { cil_protected(this) } - /** Holds if this member is `private`. */ - predicate isPrivate() { cil_private(this) } + override predicate isPrivate() { cil_private(this) } - /** Holds if this member is `internal`. */ - predicate isInternal() { cil_internal(this) } + override predicate isInternal() { cil_internal(this) } - /** Holds if this member is `sealed`. */ - predicate isSealed() { cil_sealed(this) } + override predicate isSealed() { cil_sealed(this) } - /** Holds if this member is `abstract`. */ - predicate isAbstract() { cil_abstract(this) } + override predicate isAbstract() { cil_abstract(this) } + + override predicate isStatic() { cil_static(this) } /** Holds if this member has a security attribute. */ predicate hasSecurity() { cil_security(this) } - /** Holds if this member is `static`. */ - predicate isStatic() { cil_static(this) } - override Location getLocation() { result = getDeclaringType().getLocation() } } diff --git a/csharp/ql/src/semmle/code/cil/Types.qll b/csharp/ql/src/semmle/code/cil/Types.qll index 0a07e78bb20..1bc74767d6b 100644 --- a/csharp/ql/src/semmle/code/cil/Types.qll +++ b/csharp/ql/src/semmle/code/cil/Types.qll @@ -60,6 +60,11 @@ class Class extends ValueOrRefType { Class() { this.isClass() } } +/** A `record`. */ +class Record extends Class { + Record() { this.isRecord() } +} + /** An `interface`. */ class Interface extends ValueOrRefType { Interface() { this.isInterface() } diff --git a/csharp/ql/src/semmle/code/csharp/Member.qll b/csharp/ql/src/semmle/code/csharp/Member.qll index 372e3c838a6..520df43cfb8 100644 --- a/csharp/ql/src/semmle/code/csharp/Member.qll +++ b/csharp/ql/src/semmle/code/csharp/Member.qll @@ -120,6 +120,20 @@ class Modifiable extends Declaration, @modifiable { class Member extends DotNet::Member, Modifiable, @member { /** Gets an access to this member. */ MemberAccess getAnAccess() { result.getTarget() = this } + + override predicate isPublic() { Modifiable.super.isPublic() } + + override predicate isProtected() { Modifiable.super.isProtected() } + + override predicate isPrivate() { Modifiable.super.isPrivate() } + + override predicate isInternal() { Modifiable.super.isInternal() } + + override predicate isSealed() { Modifiable.super.isSealed() } + + override predicate isAbstract() { Modifiable.super.isAbstract() } + + override predicate isStatic() { Modifiable.super.isStatic() } } /** diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index b15f7b57392..c9e89da9943 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -736,6 +736,21 @@ class Class extends RefType, @class_type { override string getAPrimaryQlClass() { result = "Class" } } +/** + * A `record`, for example + * + * ```csharp + * record R(object Prop) { + * ... + * } + * ``` + */ +class Record extends Class { + Record() { this.isRecord() } + + override string getAPrimaryQlClass() { result = "Record" } +} + /** * A class generated by the compiler from an anonymous object creation. * diff --git a/csharp/ql/src/semmle/code/dotnet/Declaration.qll b/csharp/ql/src/semmle/code/dotnet/Declaration.qll index 301f7859c66..7d6227486b0 100644 --- a/csharp/ql/src/semmle/code/dotnet/Declaration.qll +++ b/csharp/ql/src/semmle/code/dotnet/Declaration.qll @@ -58,7 +58,28 @@ class Declaration extends NamedElement, @dotnet_declaration { } /** A member of a type. */ -class Member extends Declaration, @dotnet_member { } +class Member extends Declaration, @dotnet_member { + /** Holds if this member is declared `public`. */ + predicate isPublic() { none() } + + /** Holds if this member is declared `protected.` */ + predicate isProtected() { none() } + + /** Holds if this member is `private`. */ + predicate isPrivate() { none() } + + /** Holds if this member is `internal`. */ + predicate isInternal() { none() } + + /** Holds if this member is `sealed`. */ + predicate isSealed() { none() } + + /** Holds if this member is `abstract`. */ + predicate isAbstract() { none() } + + /** Holds if this member is `static`. */ + predicate isStatic() { none() } +} /** A property. */ class Property extends Member, @dotnet_property { diff --git a/csharp/ql/src/semmle/code/dotnet/Type.qll b/csharp/ql/src/semmle/code/dotnet/Type.qll index 32cd383f913..cfb6748cf7b 100644 --- a/csharp/ql/src/semmle/code/dotnet/Type.qll +++ b/csharp/ql/src/semmle/code/dotnet/Type.qll @@ -49,6 +49,18 @@ class ValueOrRefType extends Type, @dotnet_valueorreftype { /** Gets a base type of this type, if any. */ ValueOrRefType getABaseType() { none() } + + /** Holds if this type is a `record`. */ + predicate isRecord() { + exists(Callable c | + c.getDeclaringType() = this and + c.hasName("$") and + c.getNumberOfParameters() = 0 and + c.getReturnType() = this.getABaseType*() and + c.(Member).isPublic() and + not c.(Member).isStatic() + ) + } } /** diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index 3ef4be8b9ce..59546adfbfe 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -658,7 +658,7 @@ ParenthesizedPattern.cs: # 27| 0: [TypeMention] string # 27| 2: [IntLiteral] 5 Record.cs: -# 4| [Class] Person +# 4| [Record] Person # 4| 11: [NEOperator] != #-----| 2: (Parameters) # 4| 0: [Parameter] r1 @@ -688,7 +688,7 @@ Record.cs: # 9| 1: [TupleExpr] (..., ...) # 9| 0: [ParameterAccess] access to parameter first # 9| 1: [ParameterAccess] access to parameter last -# 12| [Class] Teacher +# 12| [Record] Teacher # 12| 12: [NEOperator] != #-----| 2: (Parameters) # 12| 0: [Parameter] r1 @@ -716,7 +716,7 @@ Record.cs: # 17| 4: [AssignExpr] ... = ... # 17| 0: [PropertyCall] access to property Subject # 17| 1: [ParameterAccess] access to parameter sub -# 20| [Class] Student +# 20| [Record] Student # 20| 12: [NEOperator] != #-----| 2: (Parameters) # 20| 0: [Parameter] r1 @@ -744,7 +744,7 @@ Record.cs: # 24| 4: [AssignExpr] ... = ... # 24| 0: [PropertyCall] access to property Level # 24| 1: [ParameterAccess] access to parameter level -# 27| [Class] Person1 +# 27| [Record] Person1 # 27| 12: [NEOperator] != #-----| 2: (Parameters) # 27| 0: [Parameter] r1 @@ -771,7 +771,7 @@ Record.cs: # 27| 4: [Setter] set_LastName #-----| 2: (Parameters) # 27| 0: [Parameter] value -# 29| [Class] Teacher1 +# 29| [Record] Teacher1 # 29| 13: [NEOperator] != #-----| 2: (Parameters) # 29| 0: [Parameter] r1 @@ -795,7 +795,7 @@ Record.cs: # 29| 4: [Setter] set_Subject #-----| 2: (Parameters) # 29| 0: [Parameter] value -# 32| [Class] Student1 +# 32| [Record] Student1 # 32| 13: [NEOperator] != #-----| 2: (Parameters) # 32| 0: [Parameter] r1 @@ -819,7 +819,7 @@ Record.cs: # 32| 4: [Setter] set_Level #-----| 2: (Parameters) # 32| 0: [Parameter] value -# 35| [Class] Pet +# 35| [Record] Pet # 35| 12: [NEOperator] != #-----| 2: (Parameters) # 35| 0: [Parameter] r1 @@ -845,7 +845,7 @@ Record.cs: # 38| -1: [TypeAccess] access to type Console # 38| 0: [TypeMention] Console # 38| 0: [StringLiteral] "Shredding furniture" -# 41| [Class] Dog +# 41| [Record] Dog # 41| 12: [NEOperator] != #-----| 2: (Parameters) # 41| 0: [Parameter] r1 diff --git a/csharp/ql/test/library-tests/csharp9/record.expected b/csharp/ql/test/library-tests/csharp9/record.expected index d2a427d6554..69d7abddb31 100644 --- a/csharp/ql/test/library-tests/csharp9/record.expected +++ b/csharp/ql/test/library-tests/csharp9/record.expected @@ -198,15 +198,3 @@ members | Record.cs:41:1:52:1 | Dog | System.Object.Object() | no location | | Record.cs:41:1:52:1 | Dog | System.Object.ReferenceEquals(object, object) | no location | | Record.cs:41:1:52:1 | Dog | System.Object.~Object() | no location | -| Record.cs:54:14:54:20 | Record1 | Record1.M1() | Record.cs:56:17:56:18 | -| Record.cs:54:14:54:20 | Record1 | Record1.M2() | Record.cs:64:17:64:18 | -| Record.cs:54:14:54:20 | Record1 | Record1.Record1() | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.Equals(object) | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.Equals(object, object) | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.GetHashCode() | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.GetType() | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.MemberwiseClone() | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.Object() | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.ReferenceEquals(object, object) | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.ToString() | no location | -| Record.cs:54:14:54:20 | Record1 | System.Object.~Object() | no location | diff --git a/csharp/ql/test/library-tests/csharp9/record.ql b/csharp/ql/test/library-tests/csharp9/record.ql index 5dce739deda..3c97ee1aa84 100644 --- a/csharp/ql/test/library-tests/csharp9/record.ql +++ b/csharp/ql/test/library-tests/csharp9/record.ql @@ -1,16 +1,12 @@ import csharp -query predicate types(Class t, string i) { - t.getFile().getStem() = "Record" and - t.getABaseInterface().toStringWithTypes() = i -} +query predicate types(Record t, string i) { t.getABaseInterface().toStringWithTypes() = i } private string getMemberName(Member m) { result = m.getDeclaringType().getQualifiedName() + "." + m.toStringWithTypes() } -query predicate members(Class t, string ms, string l) { - t.getFile().getStem() = "Record" and +query predicate members(Record t, string ms, string l) { exists(Member m | t.hasMember(m) | ms = getMemberName(m) and if m.fromSource() then l = m.getLocation().toString() else l = "no location" From f555c0642efb7e3f9c96619a01fa818baaddb280 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 4 Feb 2021 08:58:52 +0100 Subject: [PATCH 196/429] Add change note --- csharp/change-notes/2021-02-04-Records.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 csharp/change-notes/2021-02-04-Records.md diff --git a/csharp/change-notes/2021-02-04-Records.md b/csharp/change-notes/2021-02-04-Records.md new file mode 100644 index 00000000000..069737e5239 --- /dev/null +++ b/csharp/change-notes/2021-02-04-Records.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Record types (`Record`) are extracted. From 83f0fad01486921d68c326bbc0d5e70443a89ac8 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 4 Feb 2021 09:01:43 +0100 Subject: [PATCH 197/429] Fix expected test AST --- .../test/library-tests/csharp9/PrintAst.expected | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index 59546adfbfe..ea3540ce4ce 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -669,10 +669,10 @@ Record.cs: # 4| 1: [Parameter] r2 # 4| 13: [Property] EqualityContract # 4| 3: [Getter] get_EqualityContract -# 6| 14: [IndexerProperty] LastName +# 6| 14: [Property] LastName # 6| -1: [TypeMention] string # 6| 3: [Getter] get_LastName -# 7| 15: [IndexerProperty] FirstName +# 7| 15: [Property] FirstName # 7| -1: [TypeMention] string # 7| 3: [Getter] get_FirstName # 9| 16: [InstanceConstructor] Person @@ -699,7 +699,7 @@ Record.cs: # 12| 1: [Parameter] r2 # 12| 14: [Property] EqualityContract # 12| 3: [Getter] get_EqualityContract -# 14| 15: [IndexerProperty] Subject +# 14| 15: [Property] Subject # 14| -1: [TypeMention] string # 14| 3: [Getter] get_Subject # 16| 16: [InstanceConstructor] Teacher @@ -761,12 +761,12 @@ Record.cs: # 27| -1: [TypeMention] string # 27| 1: [Parameter] LastName # 27| -1: [TypeMention] string -# 27| 16: [IndexerProperty] FirstName +# 27| 16: [Property] FirstName # 27| 3: [Getter] get_FirstName # 27| 4: [Setter] set_FirstName #-----| 2: (Parameters) # 27| 0: [Parameter] value -# 27| 17: [IndexerProperty] LastName +# 27| 17: [Property] LastName # 27| 3: [Getter] get_LastName # 27| 4: [Setter] set_LastName #-----| 2: (Parameters) @@ -790,7 +790,7 @@ Record.cs: # 29| -1: [TypeMention] string # 29| 2: [Parameter] Subject # 29| -1: [TypeMention] string -# 29| 17: [IndexerProperty] Subject +# 29| 17: [Property] Subject # 29| 3: [Getter] get_Subject # 29| 4: [Setter] set_Subject #-----| 2: (Parameters) @@ -834,7 +834,7 @@ Record.cs: #-----| 2: (Parameters) # 35| 0: [Parameter] Name # 35| -1: [TypeMention] string -# 35| 16: [IndexerProperty] Name +# 35| 16: [Property] Name # 35| 3: [Getter] get_Name # 35| 4: [Setter] set_Name #-----| 2: (Parameters) From 8e85145df4bd1d09750ca976439ba81592a10bf5 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 4 Feb 2021 12:51:31 -0800 Subject: [PATCH 198/429] Updated Readme file --- .../campaign/Solorigate-Readme.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md b/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md index 471fd9ed6f8..9caa17d1f3d 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md @@ -1,10 +1,10 @@ # Working with Solorigate queries -These queries hunt for Indicators of Compromise (IoCs) associated with the malicious implant code that was inserted into the SolarWinds Orion product. +In early December, 2020 a sophisticated compromise campaign was uncovered, dubbed [Solorigate](https://aka.ms/solorigate). A key feature of the campaign was a malicious software implant inserted into SolarWinds' Orion product on the build server. Studying the coding patterns and techniques used in the implant, Microsoft authored CodeQL queries as part of a larger effort to analyze our source code for any malicious modification - a brief summary of those efforts can be [found here](https://aka.ms/Solorigate-CodeQL-Blog). These queries here represent a mixture of techniques to look for code that shares features with the malicious Implant code. This ReadMe walks through what each query does and limitations of the approaches taken, suggestions for modifications, and general advice on using CodeQL to author backdoor hunting queries. There are two approaches taken with the queries; the first is to look for syntactic characteristics used in the malicious implant, things like names and particular literals. The second approach looks for semantic patterns – particular functionality and flow associated with the implant. -When editing this queries for open sourcing, we tried to find the right balance between detection capability and false positive rate, mindful that different organizations have differing resources to review the findings. +When editing this queries for open sourcing, we tried to find the right balance between detection capability and false positive rate, mindful that different organizations have differing resources to review the findings. We also excluded queries that we found to be resource intensive when executing without providing significant detective value over these queries here. In the coming weeks we will post on [our blog](https://aka.ms/CST-SE-Blog) a walk through of our experience authoring and tuning these queries, as well as discussing the challenges we saw with the queries we didn't open source. ## Syntactic queries @@ -107,15 +107,15 @@ While the results of this query are useful on their own, both to cast a wide net The malicious modifications of SolarWinds’ code took place on the build server (more details from [CrowdStrike](https://www.crowdstrike.com/blog/sunspot-malware-technical-analysis/)), so CodeQL databases used for analysis should ideally be built from the same build servers. CodeQL utilizes the same Roslyn Compiler as MSBuild, so absent the malicious actor specifically building checks for the presence of CodeQL, it is likely the injection technique utilized by the malicious actor would replicate when CodeQL was run. Alternatively, if building CodeQL databases in an independent environment, other techniques can be used to validate that the code that was compiled into the final binaries is the same as the source code in the source repository. -> ### FYI -> -> While the step-by-step details are outside the scope of this ReadMe, if the build environment is configured to perform deterministic builds (not all compilers support this, nor default to this if they do), the binaries produced by the build environment can be compared to binaries produced from the same source compiled in a distinct environment. Additionally, some compilers can be configured to emit a manifest of the source code hashes for the source files that were compiled (MSBuild puts them in the PDB files emitted during compilation), which can be compared to source hashes created in an independent environment. If the comparison of either the deterministically built binaries or source hashes do not match, that is a clear indicator that further investigation is warranted. These two techniques can be automated to provide ongoing validation of the build output. -> ->If comparing source hashes, it is strongly recommended that SHA256 rather than weaker hashes be used. This can be configured in the following Microsoft compilers by using the specified compiler flags below: -> -> * cl.exe /ZH:SHA_256 -> * ml.exe /ZH:SHA_256 -> * ml64.exe /ZH:SHA_256 -> * armasm.exe -gh:SHA_256 -> * armasm64.exe -gh:SHA_256 -> * csc.exe /checksumalgorithm:SHA256 +### FYI + +While the step-by-step details are outside the scope of this ReadMe, if the build environment is configured to perform deterministic builds (not all compilers support this, nor default to this if they do), the binaries produced by the build environment can be compared to binaries produced from the same source compiled in a distinct environment. Additionally, some compilers can be configured to emit a manifest of the source code hashes for the source files that were compiled (MSBuild puts them in the PDB files emitted during compilation), which can be compared to source hashes created in an independent environment. If the comparison of either the deterministically built binaries or source hashes do not match, that is a clear indicator that further investigation is warranted. These two techniques can be automated to provide ongoing validation of the build output. + +If comparing source hashes, it is strongly recommended that SHA256 rather than weaker hashes be used. This can be configured in the following Microsoft compilers by using the specified compiler flags below: + +* cl.exe /ZH:SHA_256 +* ml.exe /ZH:SHA_256 +* ml64.exe /ZH:SHA_256 +* armasm.exe -gh:SHA_256 +* armasm64.exe -gh:SHA_256 +* csc.exe /checksumalgorithm:SHA256 From 1d8f8286a5e58e582604c90f44cb6514a35c650b Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 4 Feb 2021 13:25:43 -0800 Subject: [PATCH 199/429] Fixes to address some of the comments during PR --- .../backdoor/DangerousNativeFunctionCall.ql | 2 +- .../ModifiedFnvFunctionDetection.qhelp | 2 +- .../ModifiedFnvFunctionDetection.ql | 4 +- .../NumberOfKnownCommandsAboveThreshold.ql | 16 ++++++ .../NumberOfKnownHashesAboveThreshold.ql | 9 ++++ .../NumberOfKnownLiteralsAboveThreshold.ql | 9 ++++ .../NumberOfKnownMethodNamesAboveThreshold.ql | 9 ++++ .../campaign/Solorigate/Solorigate.qhelp | 2 +- .../campaign/Solorigate/Solorigate.qll | 49 ++++--------------- 9 files changed, 57 insertions(+), 45 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql index f36f5b6ee2a..af1500fb215 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql @@ -52,4 +52,4 @@ from MethodCall mc where isExternMethod(mc.getTarget()) and isDangerousMethod(mc.getTarget()) -select mc, "Call to an external method $@", mc, mc.toString() +select mc, "Call to an external method '" + mc.getTarget().getName() + "'." diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp index d3abdc85f28..ffa32c5937d 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp @@ -3,7 +3,7 @@ "qhelp.dtd"> -

    The malicious code included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by 6605813339339102567 after computing the FNV-1A.

    +

    The malicious code included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by a literal after computing the FNV-1A.

    This query detects FNV-like hash calculations where there is an additional xor (with any static value) after the hash calculation loop.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql index 2e94ea4ad4e..a6e5f571ebb 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql @@ -18,12 +18,12 @@ where maybeUsedInFNVFunction(v, _, _, loop) and ( exists(BitwiseXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 | - loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() and + loop.getAControlFlowExitNode().getASuccessor*() = xor2.getAControlFlowNode() and xor2.getAnOperand() = v.getAnAccess() ) or exists(AssignXorExpr xor2 | xor2.getAnOperand() = l and additional_xor = xor2 | - loop.getAControlFlowNode().getASuccessor*() = xor2.getAControlFlowNode() and + loop.getAControlFlowExitNode().getASuccessor*() = xor2.getAControlFlowNode() and xor2.getAnOperand() = v.getAnAccess() ) ) diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql index f60d4232004..34c773636ad 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql @@ -13,6 +13,22 @@ import csharp import Solorigate +/* + * Returns the total number of Solorigate-related commands in the given enum + * + * This command list is described at https://www.fireeye.com/blog/products-and-services/2020/12/global-intrusion-campaign-leverages-software-supply-chain-compromise.html + * and the enum names are based from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + */ + +int countSolorigateCommandInEnum(Enum e) { + result = + count(string s, EnumConstant ec | + e.getAnEnumConstant() = ec and + s = ec.getName() and + s = solorigateSuspiciousCommandsInEnum() + ) +} + from Enum e, int total where total = countSolorigateCommandInEnum(e) and diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql index 830a9b48c2a..392a0d97165 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql @@ -13,6 +13,15 @@ import csharp import Solorigate +/* + * Returns the total number of Solorigate-related literales found in the project + */ + +int countSolorigateSuspiciousHash() { + result = + count(string s | exists(Literal l | s = l.getValue() and s = solorigateSuspiciousHashes())) +} + from Literal l, int total, int threshold where total = countSolorigateSuspiciousHash() and diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql index a280fefddfa..2055dda9946 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql @@ -13,6 +13,15 @@ import csharp import Solorigate +/* + * Returns the total number of Solorigate-related literales found in the project + */ + +int countSolorigateSuspiciousLiterals() { + result = + count(string s | exists(Literal l | s = l.getValue() and s = solorigateSuspiciousLiterals())) +} + from Literal l, int total, int threshold where total = countSolorigateSuspiciousLiterals() and diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql index 277d8c745bd..a3bac88cb78 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql @@ -13,6 +13,15 @@ import csharp import Solorigate +/* + * Returns the total number of Solorigate-related method names found in the project + */ + +int countSolorigateSuspiciousMethodNames() { + result = + count(string s | exists(Method m | s = m.getName() and s = solorigateSuspiciousMethodNames())) +} + from Method m, int total, int threshold where total = countSolorigateSuspiciousMethodNames() and diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp index 798ae65ba8b..19c5c2666cd 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp @@ -4,7 +4,7 @@

    The nation-state supply chain attack on SolarWinds known as Solorigate or SunBurst gave nation-state actors access to some victims' networks.

    -

    The purpose of these rules is to identify poetntially tampered code that requires further analysis

    +

    The purpose of these rules is to identify potentially tampered code that requires further analysis

    Any findings from these rules are only intended to indicate suspicious code that shares similarities with known portions of code used for this attack, but no certainty that the code is related or part of any attack.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll index 15444930fad..9a36ea4c673 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll @@ -11,7 +11,7 @@ import csharp * and https://github.com/fireeye/sunburst_countermeasures/blob/main/fnv1a_xor_hashes.txt */ -private string solorigateSuspiciousHashes() { +string solorigateSuspiciousHashes() { result = [ "10063651499895178962", "10235971842993272939", "10296494671777307979", @@ -94,15 +94,6 @@ private string solorigateSuspiciousHashes() { predicate isSolorigateHash(Literal l) { l.getValue() = solorigateSuspiciousHashes() } -/* - * Returns the total number of Solorigate-related literales found in the project - */ - -int countSolorigateSuspiciousHash() { - result = - count(string s | exists(Literal l | s = l.getValue() and s = solorigateSuspiciousHashes())) -} - /* * Returns a list of Literals used by Solorigate * @@ -110,7 +101,7 @@ int countSolorigateSuspiciousHash() { * and https://github.com/fireeye/sunburst_countermeasures/blob/main/fnv1a_xor_hashes.txt */ -private string solorigateSuspiciousLiterals() { +string solorigateSuspiciousLiterals() { result = [ "(?i)([^a-z]|^)(test)([^a-z]|$)", "(?i)(solarwinds)", "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n", @@ -157,22 +148,13 @@ private string solorigateSuspiciousLiterals() { predicate isSolorigateLiteral(Literal l) { l.getValue() = solorigateSuspiciousLiterals() } -/* - * Returns the total number of Solorigate-related literales found in the project - */ - -int countSolorigateSuspiciousLiterals() { - result = - count(string s | exists(Literal l | s = l.getValue() and s = solorigateSuspiciousLiterals())) -} - /* * Returns a list of method names used by Solorigate * * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 */ -private string solorigateSuspiciousMethodNames() { +string solorigateSuspiciousMethodNames() { result = [ "Abort", "AddFileExecutionEngine", "AddRegistryExecutionEngine", "AdjustTokenPrivileges", @@ -211,32 +193,19 @@ predicate isSolorigateSuspiciousMethodName(Method m) { m.getName() = solorigateSuspiciousMethodNames() } -/* - * Returns the total number of Solorigate-related method names found in the project - */ - -int countSolorigateSuspiciousMethodNames() { - result = - count(string s | exists(Method m | s = m.getName() and s = solorigateSuspiciousMethodNames())) -} /* - * Returns the total number of Solorigate-related commands in the given enum + * Returns a list of enum values used by Solorigate to represent commands * - * This command list is described at https://www.fireeye.com/blog/products-and-services/2020/12/global-intrusion-campaign-leverages-software-supply-chain-compromise.html - * and the enum names are based from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 + * This data was extracted from https://github.com/ITAYC0HEN/SUNBURST-Cracked/tree/a01f358965525bee34ad026acd9dfda3d488fdd8 */ -int countSolorigateCommandInEnum(Enum e) { +string solorigateSuspiciousCommandsInEnum() { result = - count(string s, EnumConstant ec | - e.getAnEnumConstant() = ec and - s = ec.getName() and - s in [ + [ "Idle", "Exit", "SetTime", "CollectSystemDescription", "UploadSystemDescription", "RunTask", "GetProcessByDescription", "KillTask", "GetFileSystemEntries", "WriteFile", "FileExists", "DeleteFile", "GetFileHash", "ReadRegistryValue", "SetRegistryValue", "DeleteRegistryValue", "GetRegistrySubKeyAndValueNames", "Reboot", "None" - ] - ) -} + ] +} \ No newline at end of file From 9470a99092b2ba161c4c420c007ffe25d33611b5 Mon Sep 17 00:00:00 2001 From: NateD-MSFT <34494373+NateD-MSFT@users.noreply.github.com> Date: Thu, 4 Feb 2021 13:32:09 -0800 Subject: [PATCH 200/429] Add KeGetCurrentProcessorNumberEx to CQE-457 whitelist Windows driver developers may call KeGetCurrentProcessorNumberEx in their driver. This function optionally may initialize a provided structure, but this initialization always occurs. The return value is the current processor being run on. As such, this query incorrectly marks calls to KeGetCurrentProcessorNumberEx that initialize a structure that is later used as risky, even though in reality the initialization always succeeds. See https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-kegetcurrentprocessornumberex --- cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll index 1a186cc4c5e..4739c7ad5cf 100644 --- a/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll +++ b/cpp/ql/src/Security/CWE/CWE-457/InitializationFunctions.qll @@ -353,7 +353,9 @@ class InitializationFunction extends Function { // Destination range is zeroed out on failure, assuming first two parameters are valid "memcpy_s", // This zeroes the memory unconditionally - "SeCreateAccessState" + "SeCreateAccessState", + // Argument initialization is optional, but always succeeds + "KeGetCurrentProcessorNumberEx" ] ) } From d5c9db42de7a95ab5d991e7c46ed86fdbef7f4b9 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 4 Feb 2021 14:26:03 -0800 Subject: [PATCH 201/429] Fixing format --- .../campaign/Solorigate/Solorigate.qll | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll index 9a36ea4c673..6947fc05bb1 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qll @@ -193,7 +193,6 @@ predicate isSolorigateSuspiciousMethodName(Method m) { m.getName() = solorigateSuspiciousMethodNames() } - /* * Returns a list of enum values used by Solorigate to represent commands * @@ -203,9 +202,9 @@ predicate isSolorigateSuspiciousMethodName(Method m) { string solorigateSuspiciousCommandsInEnum() { result = [ - "Idle", "Exit", "SetTime", "CollectSystemDescription", "UploadSystemDescription", - "RunTask", "GetProcessByDescription", "KillTask", "GetFileSystemEntries", "WriteFile", - "FileExists", "DeleteFile", "GetFileHash", "ReadRegistryValue", "SetRegistryValue", - "DeleteRegistryValue", "GetRegistrySubKeyAndValueNames", "Reboot", "None" + "Idle", "Exit", "SetTime", "CollectSystemDescription", "UploadSystemDescription", "RunTask", + "GetProcessByDescription", "KillTask", "GetFileSystemEntries", "WriteFile", "FileExists", + "DeleteFile", "GetFileHash", "ReadRegistryValue", "SetRegistryValue", "DeleteRegistryValue", + "GetRegistrySubKeyAndValueNames", "Reboot", "None" ] -} \ No newline at end of file +} From 9ef4aef28ed416a482ebb44a42622a0302dd093a Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 4 Feb 2021 16:59:38 -0800 Subject: [PATCH 202/429] Changing location for NonCryptographicHash qll Changing the TimeBomb query to path-problem (any suggestions to improve it would be welcomed, no previous experience iwth path-problem queries) --- .../backdoor/PotentialTimeBomb.ql | 14 +++++++++----- .../backdoor/ProcessNameToHashTaintFlow.ql | 2 +- .../Solorigate/ModifiedFnvFunctionDetection.ql | 2 +- .../csharp/Cryptography/NonCryptographicHashes.qll | 0 4 files changed, 11 insertions(+), 7 deletions(-) rename csharp/ql/src/{microsoft => experimental}/code/csharp/Cryptography/NonCryptographicHashes.qll (100%) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql index 3c83c0145f0..a077a372801 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -1,7 +1,7 @@ /** * @name Potential Timebomb * @description Flow from a file last modification date (very likely implant installation time) and an offset to condition statement (the trigger) - * @kind problem + * @kind path-problem * @precision Low * @problem.severity warning * @id cs/backdoor/potential-time-bomb @@ -11,6 +11,7 @@ import csharp import DataFlow +import DataFlow::PathGraph /** * Class that will help to find the source for the trigger file-modification date. @@ -121,6 +122,7 @@ private class FlowsFromTimeComparisonCallableToSelectionStatementCondition exten * which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger */ predicate isPotentialTimeBomb( + DataFlow::PathNode pathSource, DataFlow::PathNode pathSink, Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement ) { @@ -129,6 +131,7 @@ predicate isPotentialTimeBomb( DateTimeStruct dateTime, FlowsFromTimeSpanArithmeticToTimeComparisonCallable config2, Node sink2, FlowsFromTimeComparisonCallableToSelectionStatementCondition config3, Node sink3 | + pathSource.getNode() = exprNode(getLastWriteTimeMethodCall) and config1.hasFlow(exprNode(getLastWriteTimeMethodCall), sink) and timeArithmeticCall = dateTime.getATimeSpanArtithmeticCallable().getACall() and timeArithmeticCall.getAChild*() = sink.asExpr() and @@ -136,17 +139,18 @@ predicate isPotentialTimeBomb( timeComparisonCall = dateTime.getAComparisonCallable().getACall() and timeComparisonCall.getAnArgument().getAChild*() = sink2.asExpr() and config3.hasFlow(exprNode(timeComparisonCall), sink3) and - selStatement.getCondition().getAChild*() = sink3.asExpr() + selStatement.getCondition().getAChild*() = sink3.asExpr() and + pathSink.getNode() = sink3 ) } -from +from DataFlow::PathNode source, DataFlow::PathNode sink, Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement where - isPotentialTimeBomb(getLastWriteTimeMethodCall, timeArithmeticCall, timeComparisonCall, + isPotentialTimeBomb(source, sink, getLastWriteTimeMethodCall, timeArithmeticCall, timeComparisonCall, selStatement) -select selStatement, +select selStatement, source, sink, "Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger.", timeComparisonCall, timeComparisonCall.toString(), timeArithmeticCall, "an offset", getLastWriteTimeMethodCall, "last modification time of a file" diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql index 5b1f8faeaf6..277a6668a2d 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -12,7 +12,7 @@ import csharp import DataFlow -import microsoft.code.csharp.Cryptography.NonCryptographicHashes +import experimental.code.csharp.Cryptography.NonCryptographicHashes class DataFlowFromMethodToHash extends TaintTracking::Configuration { DataFlowFromMethodToHash() { this = "DataFlowFromMethodNameToHashFunction" } diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql index a6e5f571ebb..e9f81596e04 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql @@ -11,7 +11,7 @@ import csharp import Solorigate -import microsoft.code.csharp.Cryptography.NonCryptographicHashes +import experimental.code.csharp.Cryptography.NonCryptographicHashes from Variable v, Literal l, LoopStmt loop, Expr additional_xor where diff --git a/csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll similarity index 100% rename from csharp/ql/src/microsoft/code/csharp/Cryptography/NonCryptographicHashes.qll rename to csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll From 3dc1b81d655d3b34cbfb4878c39c1a5cd8279c26 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 4 Feb 2021 17:54:35 -0800 Subject: [PATCH 203/429] Changing ProcessNameToHash query to path-problem. Any additional feedback will be welcomed --- .../backdoor/PotentialTimeBomb.ql | 19 +++++++++---------- .../backdoor/ProcessNameToHashTaintFlow.ql | 12 ++++++------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql index a077a372801..7558a971657 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -122,16 +122,15 @@ private class FlowsFromTimeComparisonCallableToSelectionStatementCondition exten * which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger */ predicate isPotentialTimeBomb( - DataFlow::PathNode pathSource, DataFlow::PathNode pathSink, - Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, - SelectionStmt selStatement + DataFlow::PathNode pathSource, DataFlow::PathNode pathSink, Call getLastWriteTimeMethodCall, + Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement ) { exists( FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable config1, Node sink, DateTimeStruct dateTime, FlowsFromTimeSpanArithmeticToTimeComparisonCallable config2, Node sink2, FlowsFromTimeComparisonCallableToSelectionStatementCondition config3, Node sink3 | - pathSource.getNode() = exprNode(getLastWriteTimeMethodCall) and + pathSource.getNode() = exprNode(getLastWriteTimeMethodCall) and config1.hasFlow(exprNode(getLastWriteTimeMethodCall), sink) and timeArithmeticCall = dateTime.getATimeSpanArtithmeticCallable().getACall() and timeArithmeticCall.getAChild*() = sink.asExpr() and @@ -144,13 +143,13 @@ predicate isPotentialTimeBomb( ) } -from DataFlow::PathNode source, DataFlow::PathNode sink, - Call getLastWriteTimeMethodCall, Call timeArithmeticCall, Call timeComparisonCall, - SelectionStmt selStatement +from + DataFlow::PathNode source, DataFlow::PathNode sink, Call getLastWriteTimeMethodCall, + Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement where - isPotentialTimeBomb(source, sink, getLastWriteTimeMethodCall, timeArithmeticCall, timeComparisonCall, - selStatement) -select selStatement, source, sink, + isPotentialTimeBomb(source, sink, getLastWriteTimeMethodCall, timeArithmeticCall, + timeComparisonCall, selStatement) +select selStatement, source, sink, "Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger.", timeComparisonCall, timeComparisonCall.toString(), timeArithmeticCall, "an offset", getLastWriteTimeMethodCall, "last modification time of a file" diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql index 277a6668a2d..96363bbadff 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -2,7 +2,7 @@ * @name ProcessName to hash function flow * @description Flow from a function retrieving process name to a hash function * NOTE: This query is an example of a query that may be useful for detecting potential backdoors, and Solorigate is just one such example that uses this mechanism. - * @kind problem + * @kind path-problem * @tags security * solorigate * @problem.severity warning @@ -11,7 +11,7 @@ */ import csharp -import DataFlow +import DataFlow::PathGraph import experimental.code.csharp.Cryptography.NonCryptographicHashes class DataFlowFromMethodToHash extends TaintTracking::Configuration { @@ -49,8 +49,8 @@ predicate isSuspiciousPropertyName(PropertyRead pr) { pr.getTarget().getQualifiedName() = "System.Diagnostics.Process.ProcessName" } -from Node src, Node sink, DataFlowFromMethodToHash conf -where conf.hasFlow(src, sink) -select src, +from DataFlow::PathNode src, DataFlow::PathNode sink, DataFlowFromMethodToHash conf +where conf.hasFlow(src.getNode(), sink.getNode()) +select src.getNode(), src, sink, "The hash is calculated on the process name $@, may be related to a backdoor. Please review the code for possible malicious intent.", - sink, "here" + sink.getNode(), "here" From a416a089b42d6924c9ee81eb9ffee7d3c69e8027 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 5 Feb 2021 09:48:54 +0100 Subject: [PATCH 204/429] Update cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md Co-authored-by: Jonas Jensen --- .../2020-02-04-unsigned-difference-expression-compared-zero.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md index 31f2b035267..d4a6ebafa0c 100644 --- a/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md +++ b/cpp/change-notes/2020-02-04-unsigned-difference-expression-compared-zero.md @@ -1,2 +1,2 @@ lgtm -* A new query (`cpp/unsigned-difference-expression-compared-zero`) has been added. The query finds unsigned subtractions used in relational comparisons with the value 0. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4745. \ No newline at end of file +* A new query (`cpp/unsigned-difference-expression-compared-zero`) is run but not yet displayed on LGTM. The query finds unsigned subtractions used in relational comparisons with the value 0. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4745. From a66743192e72e7f12f7f214c74153d5ad783fc4a Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 5 Feb 2021 10:58:47 +0100 Subject: [PATCH 205/429] Python: Fix typo in docs Co-authored-by: yoff --- python/ql/src/semmle/python/ApiGraphs.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 6bacac72c3a..20d5c848a0d 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -274,7 +274,7 @@ module API { * this node, it is reachable via `moduleImport("foo").getMember("bar").getMember("baz")` and * thus `fbb.quux` is reachable via the path mentioned above. * - * When we see `from foo.bar.baz import quux as fbb` a similar thing happens. First, `foo.bar.baz` + * When we see `from foo.bar.baz import quux as fbbq` a similar thing happens. First, `foo.bar.baz` * is seen as a use of the API graph node as before. Then `import quux as fbbq` is seen as * a member lookup of `quux` on the API graph node for `foo.bar.baz`, and then finally the * data-flow node `fbbq` is marked as a use of the same path mentioned above. From 55b0dbd7b89a2c10b4bc779dbc20e4661fa8e4db Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 5 Feb 2021 10:02:31 +0000 Subject: [PATCH 206/429] C++: Autoformat. --- cpp/ql/src/semmle/code/cpp/Specifier.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Specifier.qll b/cpp/ql/src/semmle/code/cpp/Specifier.qll index 8331d0dfacc..1c1eb0c090a 100644 --- a/cpp/ql/src/semmle/code/cpp/Specifier.qll +++ b/cpp/ql/src/semmle/code/cpp/Specifier.qll @@ -207,7 +207,7 @@ class AlignAs extends Attribute, @alignas { * A GNU `format` attribute of the form `__attribute__((format(archetype, format-index, first-arg)))` * that declares a function to accept a `printf` style format string. For example the attribute * on the following declaration: - * ``` + * ``` * int myPrintf(const char *format, ...) __attribute__((format(printf, 1, 2))); * ``` */ From 6c8dfb253d8e356b86c8a2354dae273a8bcfa5ac Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 5 Feb 2021 12:42:41 +0100 Subject: [PATCH 207/429] Python: Use `flowsTo` instead of `hasLocalSource` Co-authored-by: yoff --- .../python/dataflow/new/internal/DataFlowPublic.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index dcc175276f8..19677566be9 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -451,7 +451,7 @@ class LocalSourceNode extends Node { } /** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */ - cached + pragma[inline] predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) } /** @@ -509,7 +509,7 @@ private module Cached { */ cached predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) { - hasLocalSource(ref.getObject(), base) and + base.flowsTo(ref.getObject()) and ref.getAttributeName() = attr } @@ -518,7 +518,7 @@ private module Cached { */ cached predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) { - hasLocalSource(ref.getObject(), base) and + base.flowsTo(ref.getObject()) and not exists(ref.getAttributeName()) } @@ -530,7 +530,7 @@ private module Cached { exists(CfgNode n, CallNode call_node | call.asCfgNode() = call_node and n.asCfgNode() = call_node.getFunction() | - hasLocalSource(n, func) + func.flowsTo(n) ) } } From 78cb53449d9f6c3a5c72ecd29796264c4f516bbd Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 5 Feb 2021 12:47:26 +0100 Subject: [PATCH 208/429] Python: Slight cleanup of `Cached::call` Makes it more similar to the other functions in this module. --- .../semmle/python/dataflow/new/internal/DataFlowPublic.qll | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 19677566be9..f2519192f27 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -527,10 +527,9 @@ private module Cached { */ cached predicate call(LocalSourceNode func, Node call) { - exists(CfgNode n, CallNode call_node | - call.asCfgNode() = call_node and n.asCfgNode() = call_node.getFunction() - | - func.flowsTo(n) + exists(CfgNode n | + func.flowsTo(n) and + n.asCfgNode() = call.asCfgNode().(CallNode).getFunction() ) } } From 5f17fa83663a53ae1da5339a760cfc4f8e17b506 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Thu, 21 Jan 2021 15:26:05 +0000 Subject: [PATCH 209/429] Docs: Add outline for CWE coverage page --- docs/codeql/query-help/codeql-cwe-coverage.md | 25 +++++++++++++++++++ docs/codeql/query-help/conf.py | 5 +++- docs/codeql/query-help/index.rst | 4 +++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 docs/codeql/query-help/codeql-cwe-coverage.md diff --git a/docs/codeql/query-help/codeql-cwe-coverage.md b/docs/codeql/query-help/codeql-cwe-coverage.md new file mode 100644 index 00000000000..245318a5258 --- /dev/null +++ b/docs/codeql/query-help/codeql-cwe-coverage.md @@ -0,0 +1,25 @@ +# CodeQL CWE coverage + +An overview of the coverage of MITRE's Common Weakness Enumeration (CWE) for the latest release of CodeQL. + +## About CWEs + +The CWE categorization contains several types of entity, collectively known as CWEs. The CWEs that we consider in this report are only those of the types: + +- Weakness Class +- Weakness Base +- Weakness Variant +- Compound Element + +Other types of CWE do not correspond directly to weaknesses, so are omitted. + +The CWE categorization includes relationships between entities, in particular a parent-child relationship. +These relationships are associated with Views (another kind of CWE entity). For the purposes of coverage claims, we use the "[Research View](https://cwe.mitre.org/data/definitions/1000.html)." + +Every security query is associated with one or more CWEs, which are the most precise CWEs that are covered by that query. +Overall coverage is claimed for the most-precise CWEs, as well as for any of their ancestors in the View. + +## Overview + + + diff --git a/docs/codeql/query-help/conf.py b/docs/codeql/query-help/conf.py index 0016a489f07..f3d4090f952 100644 --- a/docs/codeql/query-help/conf.py +++ b/docs/codeql/query-help/conf.py @@ -23,7 +23,10 @@ master_doc = 'index' project = u'CodeQL query help' # Add md parser to process query help markdown files -extensions =['recommonmark'] +extensions = [ + 'recommonmark', + 'sphinx_markdown_tables', +] source_suffix = { '.rst': 'restructuredtext', diff --git a/docs/codeql/query-help/index.rst b/docs/codeql/query-help/index.rst index 5c523650d70..10e4b0dff20 100644 --- a/docs/codeql/query-help/index.rst +++ b/docs/codeql/query-help/index.rst @@ -20,6 +20,9 @@ View the query help for the queries included in the ``code-scanning``, ``securit - A link to the query in the `CodeQL repository `__. - A description of the potential vulnerability that the query identifies and a recommendation for how to avoid introducing the problem to your code. + +For a full list of the CWEs covered by these queries, see ":doc:`CodeQL CWE coverage `." + .. toctree:: :hidden: :titlesonly: @@ -30,4 +33,5 @@ View the query help for the queries included in the ``code-scanning``, ``securit java javascript python + codeql-cwe-coverage From 6a46be23798e70b508ad7cbe0567c0c0f9657460 Mon Sep 17 00:00:00 2001 From: Shati Patel <42641846+shati-patel@users.noreply.github.com> Date: Mon, 1 Feb 2021 16:17:44 +0000 Subject: [PATCH 210/429] Install sphinx extension for building markdown tables --- .github/workflows/generate-query-help-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-query-help-docs.yml b/.github/workflows/generate-query-help-docs.yml index 031bf97e728..e3af19c6dea 100644 --- a/.github/workflows/generate-query-help-docs.yml +++ b/.github/workflows/generate-query-help-docs.yml @@ -50,7 +50,7 @@ jobs: uses: ammaraskar/sphinx-action@8b4f60114d7fd1faeba1a712269168508d4750d2 # v0.4 with: docs-folder: "query-help/" - pre-build-command: "python -m pip install --upgrade recommonmark" + pre-build-command: "python -m pip install --upgrade recommonmark && python -m pip install --upgrade sphinx-markdown-tables" build-command: "sphinx-build -b dirhtml . _build" - name: Upload HTML artifacts uses: actions/upload-artifact@v2 From b39cbf82c6982c4727c957720c427a7ee3215afa Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 5 Feb 2021 14:41:42 +0100 Subject: [PATCH 211/429] Python: Port Flask models to use API graphs Most of the type trackers in this model were easily replaceable with uses of the API graph, but the ones for tracking subclasses are problematic, as these take us out of the API graph. --- .../ql/src/semmle/python/frameworks/Flask.qll | 241 ++---------------- 1 file changed, 27 insertions(+), 214 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 68f81e32ceb..ecfdf2d5981 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -9,6 +9,7 @@ private import semmle.python.dataflow.new.RemoteFlowSources private import semmle.python.dataflow.new.TaintTracking private import semmle.python.Concepts private import semmle.python.frameworks.Werkzeug +private import semmle.python.ApiGraphs /** * Provides models for the `flask` PyPI package. @@ -19,62 +20,20 @@ private module FlaskModel { // flask // --------------------------------------------------------------------------- /** Gets a reference to the `flask` module. */ - private DataFlow::Node flask(DataFlow::TypeTracker t) { - t.start() and - result = DataFlow::importNode("flask") - or - exists(DataFlow::TypeTracker t2 | result = flask(t2).track(t2, t)) - } - - /** Gets a reference to the `flask` module. */ - DataFlow::Node flask() { result = flask(DataFlow::TypeTracker::end()) } + API::Node flask() { result = API::moduleImport("flask") } /** * Gets a reference to the attribute `attr_name` of the `flask` module. - * WARNING: Only holds for a few predefined attributes. */ - private DataFlow::Node flask_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in ["request", "make_response", "Response", "views"] and - ( - t.start() and - result = DataFlow::importNode("flask" + "." + attr_name) - or - t.startInAttr(attr_name) and - result = flask() - ) - or - // Due to bad performance when using normal setup with `flask_attr(t2, attr_name).track(t2, t)` - // we have inlined that code and forced a join - exists(DataFlow::TypeTracker t2 | - exists(DataFlow::StepSummary summary | - flask_attr_first_join(t2, attr_name, result, summary) and - t = t2.append(summary) - ) - ) - } - - pragma[nomagic] - private predicate flask_attr_first_join( - DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary - ) { - DataFlow::StepSummary::step(flask_attr(t2, attr_name), res, summary) - } - - /** - * Gets a reference to the attribute `attr_name` of the `flask` module. - * WARNING: Only holds for a few predefined attributes. - */ - private DataFlow::Node flask_attr(string attr_name) { - result = flask_attr(DataFlow::TypeTracker::end(), attr_name) - } + private API::Node flask_attr(string attr_name) { result = flask().getMember(attr_name) } /** Provides models for the `flask` module. */ module flask { /** Gets a reference to the `flask.request` object. */ - DataFlow::Node request() { result = flask_attr("request") } + API::Node request() { result = flask_attr("request") } /** Gets a reference to the `flask.make_response` function. */ - DataFlow::Node make_response() { result = flask_attr("make_response") } + DataFlow::Node make_response() { result = flask_attr("make_response").getAUse() } /** * Provides models for the `flask.Flask` class @@ -83,157 +42,49 @@ private module FlaskModel { */ module Flask { /** Gets a reference to the `flask.Flask` class. */ - private DataFlow::Node classRef(DataFlow::TypeTracker t) { - t.start() and - result = DataFlow::importNode("flask.Flask") - or - t.startInAttr("Flask") and - result = flask() - or - exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t)) - } - - /** Gets a reference to the `flask.Flask` class. */ - DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) } - - /** - * A source of instances of `flask.Flask`, extend this class to model new instances. - * - * This can include instantiations of the class, return values from function - * calls, or a special parameter that will be set when functions are called by an external - * library. - * - * Use the predicate `Flask::instance()` to get references to instances of `flask.Flask`. - */ - abstract class InstanceSource extends DataFlow::Node { } - - /** A direct instantiation of `flask.Flask`. */ - private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { - override CallNode node; - - ClassInstantiation() { node.getFunction() = classRef().asCfgNode() } - } + API::Node classRef() { result = flask().getMember("Flask") } /** Gets a reference to an instance of `flask.Flask` (a flask application). */ - private DataFlow::Node instance(DataFlow::TypeTracker t) { - t.start() and - result instanceof InstanceSource - or - exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) - } - - /** Gets a reference to an instance of `flask.Flask` (a flask application). */ - DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) } + API::Node instance() { result = classRef().getReturn() } /** * Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application). - * WARNING: Only holds for a few predefined attributes. */ - private DataFlow::Node instance_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in ["route", "add_url_rule", "make_response"] and - t.startInAttr(attr_name) and - result = flask::Flask::instance() - or - // Due to bad performance when using normal setup with `instance_attr(t2, attr_name).track(t2, t)` - // we have inlined that code and forced a join - exists(DataFlow::TypeTracker t2 | - exists(DataFlow::StepSummary summary | - instance_attr_first_join(t2, attr_name, result, summary) and - t = t2.append(summary) - ) - ) - } - - pragma[nomagic] - private predicate instance_attr_first_join( - DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, - DataFlow::StepSummary summary - ) { - DataFlow::StepSummary::step(instance_attr(t2, attr_name), res, summary) - } - - /** - * Gets a reference to the attribute `attr_name` of an instance of `flask.Flask` (a flask application). - * WARNING: Only holds for a few predefined attributes. - */ - private DataFlow::Node instance_attr(string attr_name) { - result = instance_attr(DataFlow::TypeTracker::end(), attr_name) - } + private API::Node instance_attr(string attr_name) { result = instance().getMember(attr_name) } /** Gets a reference to the `route` method on an instance of `flask.Flask`. */ - DataFlow::Node route() { result = instance_attr("route") } + API::Node route() { result = instance_attr("route") } /** Gets a reference to the `add_url_rule` method on an instance of `flask.Flask`. */ - DataFlow::Node add_url_rule() { result = instance_attr("add_url_rule") } + API::Node add_url_rule() { result = instance_attr("add_url_rule") } /** Gets a reference to the `make_response` method on an instance of `flask.Flask`. */ // HACK: We can't call this predicate `make_response` since shadowing is // completely disallowed in QL. I added an underscore to move things forward for // now :( - DataFlow::Node make_response_() { result = instance_attr("make_response") } - - /** Gets a reference to the `response_class` attribute on the `flask.Flask` class or an instance. */ - private DataFlow::Node response_class(DataFlow::TypeTracker t) { - t.startInAttr("response_class") and - result in [classRef(), instance()] - or - exists(DataFlow::TypeTracker t2 | result = response_class(t2).track(t2, t)) - } + API::Node make_response_() { result = instance_attr("make_response") } /** * Gets a reference to the `response_class` attribute on the `flask.Flask` class or an instance. * * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.response_class */ - DataFlow::Node response_class() { result = response_class(DataFlow::TypeTracker::end()) } + API::Node response_class() { result = [classRef(), instance()].getMember("response_class") } } // ------------------------------------------------------------------------- // flask.views // ------------------------------------------------------------------------- /** Gets a reference to the `flask.views` module. */ - DataFlow::Node views() { result = flask_attr("views") } + DataFlow::Node views() { result = flask_attr("views").getAUse() } /** Provides models for the `flask.views` module */ module views { /** * Gets a reference to the attribute `attr_name` of the `flask.views` module. - * WARNING: Only holds for a few predefined attributes. - */ - private DataFlow::Node views_attr(DataFlow::TypeTracker t, string attr_name) { - attr_name in ["View", "MethodView"] and - ( - t.start() and - result = DataFlow::importNode("flask.views" + "." + attr_name) - or - t.startInAttr(attr_name) and - result = views() - ) - or - // Due to bad performance when using normal setup with `views_attr(t2, attr_name).track(t2, t)` - // we have inlined that code and forced a join - exists(DataFlow::TypeTracker t2 | - exists(DataFlow::StepSummary summary | - views_attr_first_join(t2, attr_name, result, summary) and - t = t2.append(summary) - ) - ) - } - - pragma[nomagic] - private predicate views_attr_first_join( - DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, - DataFlow::StepSummary summary - ) { - DataFlow::StepSummary::step(views_attr(t2, attr_name), res, summary) - } - - /** - * Gets a reference to the attribute `attr_name` of the `flask.views` module. - * WARNING: Only holds for a few predefined attributes. */ private DataFlow::Node views_attr(string attr_name) { - result = views_attr(DataFlow::TypeTracker::end(), attr_name) + result = flask().getMember("views").getMember(attr_name).getAUse() } /** @@ -287,15 +138,7 @@ private module FlaskModel { */ module Response { /** Gets a reference to the `flask.Response` class. */ - private DataFlow::Node classRef(DataFlow::TypeTracker t) { - t.start() and - result in [flask_attr("Response"), flask::Flask::response_class()] - or - exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t)) - } - - /** Gets a reference to the `flask.Response` class. */ - DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) } + API::Node classRef() { result = [flask_attr("Response"), flask::Flask::response_class()] } /** * A source of instances of `flask.Response`, extend this class to model new instances. @@ -312,7 +155,7 @@ private module FlaskModel { private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { override CallNode node; - ClassInstantiation() { node.getFunction() = classRef().asCfgNode() } + ClassInstantiation() { node.getFunction() = classRef().getAUse().asCfgNode() } override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) } @@ -338,15 +181,7 @@ private module FlaskModel { } /** Gets a reference to an instance of `flask.Response`. */ - private DataFlow::Node instance(DataFlow::TypeTracker t) { - t.start() and - result instanceof InstanceSource - or - exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t)) - } - - /** Gets a reference to an instance of `flask.Response`. */ - DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) } + API::Node instance() { result = classRef().getReturn() } } // --------------------------------------------------------------------------- @@ -445,7 +280,7 @@ private module FlaskModel { private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CfgNode { override CallNode node; - FlaskAppRouteCall() { node.getFunction() = flask::Flask::route().asCfgNode() } + FlaskAppRouteCall() { node.getFunction() = flask::Flask::route().getAUse().asCfgNode() } override DataFlow::Node getUrlPatternArg() { result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")] @@ -462,7 +297,9 @@ private module FlaskModel { private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CfgNode { override CallNode node; - FlaskAppAddUrlRuleCall() { node.getFunction() = flask::Flask::add_url_rule().asCfgNode() } + FlaskAppAddUrlRuleCall() { + node.getFunction() = flask::Flask::add_url_rule().getAUse().asCfgNode() + } override DataFlow::Node getUrlPatternArg() { result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")] @@ -511,41 +348,16 @@ private module FlaskModel { * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request */ private class RequestSource extends RemoteFlowSource::Range { - RequestSource() { this = flask::request() } + RequestSource() { this = flask::request().getAUse() } override string getSourceType() { result = "flask.request" } } private module FlaskRequestTracking { - /** Gets a reference to the `get_data` attribute of a Flask request. */ - private DataFlow::Node get_data(DataFlow::TypeTracker t) { - t.startInAttr("get_data") and - result = flask::request() - or - exists(DataFlow::TypeTracker t2 | result = get_data(t2).track(t2, t)) - } - - /** Gets a reference to the `get_data` attribute of a Flask request. */ - DataFlow::Node get_data() { result = get_data(DataFlow::TypeTracker::end()) } - - /** Gets a reference to the `get_json` attribute of a Flask request. */ - private DataFlow::Node get_json(DataFlow::TypeTracker t) { - t.startInAttr("get_json") and - result = flask::request() - or - exists(DataFlow::TypeTracker t2 | result = get_json(t2).track(t2, t)) - } - - /** Gets a reference to the `get_json` attribute of a Flask request. */ - DataFlow::Node get_json() { result = get_json(DataFlow::TypeTracker::end()) } - /** Gets a reference to either of the `get_json` or `get_data` attributes of a Flask request. */ DataFlow::Node tainted_methods(string attr_name) { - result = get_data() and - attr_name = "get_data" - or - result = get_json() and - attr_name = "get_json" + attr_name in ["get_data", "get_json"] and + result = flask::request().getMember(attr_name).getAUse() } } @@ -560,7 +372,8 @@ private module FlaskModel { RequestInputAccess() { // attributes exists(AttrNode attr | - this.asCfgNode() = attr and attr.getObject(attr_name) = flask::request().asCfgNode() + this.asCfgNode() = attr and + attr.getObject(attr_name) = flask::request().getAUse().asCfgNode() | attr_name in [ // str @@ -645,7 +458,7 @@ private module FlaskModel { FlaskMakeResponseCall() { node.getFunction() = flask::make_response().asCfgNode() or - node.getFunction() = flask::Flask::make_response_().asCfgNode() + node.getFunction() = flask::Flask::make_response_().getAUse().asCfgNode() } override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) } From ef600575cace741e796cf7c8fdcc33a45e7a52c1 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 5 Feb 2021 16:51:29 +0100 Subject: [PATCH 212/429] Python: Add API graph support for subclasses --- python/ql/src/semmle/python/ApiGraphs.qll | 13 +++++++++++++ .../experimental/dataflow/ApiGraphs/test.py | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 20d5c848a0d..8f48be66650 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -92,6 +92,11 @@ module API { */ Node getReturn() { result = getASuccessor(Label::return()) } + /** + * Gets a node representing a subclass of the class represented by this node. + */ + Node getASubclass() { result = getASuccessor(Label::subclass()) } + /** * Gets a string representation of the lexicographically least among all shortest access paths * from the root to this node. @@ -358,6 +363,12 @@ module API { // Calling a node that is a use of `base` lbl = Label::return() and ref = pred.getACall() + or + // Subclassing a node + lbl = Label::subclass() and + exists(DataFlow::Node superclass | pred.flowsTo(superclass) | + ref.asExpr().(ClassExpr).getABase() = superclass.asExpr() + ) ) } @@ -468,4 +479,6 @@ private module Label { /** Gets the `return` edge label. */ string return() { result = "getReturn()" } + + string subclass() { result = "getASubclass()" } } diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py index b250c7985e2..8849253b477 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -79,3 +79,20 @@ def f(): from unknown import * #$ use=moduleImport("unknown") hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn() + + +# Subclasses + +from flask.views import View #$ use=moduleImport("flask").getMember("views").getMember("View") + +class MyView(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass() + pass + +instance = MyView() #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getReturn() + +def internal(): + from pflask.views import View #$ use=moduleImport("pflask").getMember("views").getMember("View") + class IntMyView(View): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass() + pass + + int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn() From 681e6a9303d6ce3f98fd4ebc8c7c02e434c1da8e Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Fri, 5 Feb 2021 09:02:59 -0800 Subject: [PATCH 213/429] Adding Solorigate context for the generic backdoor queries. --- .../backdoor/DangerousNativeFunctionCall.qhelp | 6 ++++++ .../Security Features/backdoor/PotentialTimeBomb.qhelp | 6 ++++++ .../backdoor/ProcessNameToHashTaintFlow.qhelp | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp index 8d1aff62988..75bd300601e 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp @@ -5,4 +5,10 @@

    This query finds native calls to external functions that are often used in creating backdoors or are generally attributed to unsafe code practices.

    + + +

    Any findings from this rules is only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack, but no certainty that the code is related or part of any attack.

    +

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp index 32f0e200c15..c9cecee8374 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp @@ -5,4 +5,10 @@

    This query finds if there exists a DataFlow from a file last modification date (very likely implant installation time) and an offset to a condition statement (the trigger) that controls code execution.

    + + +

    Any findings from this rules is only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack, but no certainty that the code is related or part of any attack.

    +

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    +
    +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp index 7281ddb28bb..12eb83191ac 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp @@ -6,4 +6,10 @@

    This query detects code flow from ProcessName property on the Process class into a hash function.

    Such flow is often used in code backdoors to detect runnig processes and compare them to an obfuscated list of antivirus processes to aviod detection.

    + + +

    Any findings from this rules is only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack, but no certainty that the code is related or part of any attack.

    +

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    +
    + \ No newline at end of file From d48a713f3079e1a6805d95dfc04ead6a8881d674 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Fri, 5 Feb 2021 09:27:08 -0800 Subject: [PATCH 214/429] Fixing cutom edges predicate --- .../backdoor/PotentialTimeBomb.ql | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql index 7558a971657..332df2d2a28 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -11,7 +11,32 @@ import csharp import DataFlow -import DataFlow::PathGraph + +query predicate nodes = PathGraph::nodes/3; + +query predicate edges(DataFlow::PathNode a, DataFlow::PathNode b) { + PathGraph::edges(a, b) + or + exists( + FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable conf1, + FlowsFromTimeSpanArithmeticToTimeComparisonCallable conf2 + | + conf1 = a.getConfiguration() and + conf1.isSink(a.getNode()) and + conf2 = b.getConfiguration() and + b.isSource() + ) + or + exists( + FlowsFromTimeSpanArithmeticToTimeComparisonCallable conf1, + FlowsFromTimeComparisonCallableToSelectionStatementCondition conf2 + | + conf1 = a.getConfiguration() and + conf1.isSink(a.getNode()) and + conf2 = b.getConfiguration() and + b.isSource() + ) +} /** * Class that will help to find the source for the trigger file-modification date. From 7f3c6acd086e18cfabfb083debc4718470e7b496 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 5 Feb 2021 21:54:35 +0100 Subject: [PATCH 215/429] Python: Handle class attribute references in API graph This is slightly dubious, and should really be in the currently unimplemented "def" counterpart to the "use" bits we already have. However, it seems to work correctly, and in the spirit of moving things along, this seemed like the easier solution. We can always replace the implementation with the "proper" approach at a later point. --- python/ql/src/semmle/python/ApiGraphs.qll | 4 ++-- python/ql/test/experimental/dataflow/ApiGraphs/test.py | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 8f48be66650..3169592c8b2 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -356,9 +356,9 @@ module API { // the relationship between `pred` and `ref`. use(base, src) and pred = trackUseNode(src) | - // Reading an attribute on a node that is a use of `base`: + // Referring to an attribute on a node that is a use of `base`: lbl = Label::memberFromRef(ref) and - ref = pred.getAnAttributeRead() + ref = pred.getAnAttributeReference() or // Calling a node that is a use of `base` lbl = Label::return() and diff --git a/python/ql/test/experimental/dataflow/ApiGraphs/test.py b/python/ql/test/experimental/dataflow/ApiGraphs/test.py index 8849253b477..179f0f522df 100644 --- a/python/ql/test/experimental/dataflow/ApiGraphs/test.py +++ b/python/ql/test/experimental/dataflow/ApiGraphs/test.py @@ -86,13 +86,17 @@ hello() #$ MISSING: use=moduleImport("unknown").getMember("hello").getReturn() from flask.views import View #$ use=moduleImport("flask").getMember("views").getMember("View") class MyView(View): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass() - pass + myvar = 45 #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("myvar") + def my_method(self): #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getMember("my_method") + pass instance = MyView() #$ use=moduleImport("flask").getMember("views").getMember("View").getASubclass().getReturn() def internal(): from pflask.views import View #$ use=moduleImport("pflask").getMember("views").getMember("View") class IntMyView(View): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass() - pass + my_internal_var = 35 #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_var") + def my_internal_method(self): #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getMember("my_internal_method") + pass int_instance = IntMyView() #$ use=moduleImport("pflask").getMember("views").getMember("View").getASubclass().getReturn() From 5bfde2c0f2845df08036084f49fa3824aebbd263 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 5 Feb 2021 21:56:57 +0100 Subject: [PATCH 216/429] Python: Fix overly broad class attribute node class This is not strictly necessary, but it was bothering me that this simply covered _all_ nodes that were both definitions and names at the same time. Now it actually encompasses what the documentation claims it does. --- .../ql/src/semmle/python/dataflow/new/internal/Attributes.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll b/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll index cfe05cb3173..1bd5f961a36 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/Attributes.qll @@ -159,7 +159,9 @@ private class SetAttrCallAsAttrWrite extends AttrWrite, CfgNode { * Instances of this class correspond to the `NameNode` for `attr`, and also gives access to `value` by * virtue of being a `DefinitionNode`. */ -private class ClassAttributeAssignmentNode extends DefinitionNode, NameNode { } +private class ClassAttributeAssignmentNode extends DefinitionNode, NameNode { + ClassAttributeAssignmentNode() { this.getScope() = any(ClassExpr c).getInnerScope() } +} /** * An attribute assignment via a class field, e.g. From 3d2548ed28c7902e7d085f54e8ceb67f295b6a7c Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 5 Feb 2021 21:58:08 +0100 Subject: [PATCH 217/429] Python: Get rid of remaining type trackers in Flask model At this point, we may want to reconsider whether we really want the deeply-nested module structure we had before (and which made the type trackers somewhat bearable). There's also a question of how we can make this a bit more smooth. I think we need to consider exactly how we would like the interface to this to work. --- .../ql/src/semmle/python/frameworks/Flask.qll | 85 ++++--------------- 1 file changed, 18 insertions(+), 67 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index ecfdf2d5981..178d089b2ea 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -76,17 +76,10 @@ private module FlaskModel { // flask.views // ------------------------------------------------------------------------- /** Gets a reference to the `flask.views` module. */ - DataFlow::Node views() { result = flask_attr("views").getAUse() } + API::Node views() { result = flask_attr("views") } /** Provides models for the `flask.views` module */ module views { - /** - * Gets a reference to the attribute `attr_name` of the `flask.views` module. - */ - private DataFlow::Node views_attr(string attr_name) { - result = flask().getMember("views").getMember(attr_name).getAUse() - } - /** * Provides models for the `flask.views.View` class and subclasses. * @@ -94,18 +87,9 @@ private module FlaskModel { */ module View { /** Gets a reference to the `flask.views.View` class or any subclass. */ - private DataFlow::Node subclassRef(DataFlow::TypeTracker t) { - t.start() and - result = views_attr(["View", "MethodView"]) - or - // subclasses in project code - result.asExpr().(ClassExpr).getABase() = subclassRef(t.continue()).asExpr() - or - exists(DataFlow::TypeTracker t2 | result = subclassRef(t2).track(t2, t)) + API::Node subclassRef() { + result = views().getMember(["View", "MethodView"]).getASubclass*() } - - /** Gets a reference to the `flask.views.View` class or any subclass. */ - DataFlow::Node subclassRef() { result = subclassRef(DataFlow::TypeTracker::end()) } } /** @@ -114,19 +98,8 @@ private module FlaskModel { * See https://flask.palletsprojects.com/en/1.1.x/views/#method-based-dispatching. */ module MethodView { - /** Gets a reference to the `flask.views.View` class or any subclass. */ - private DataFlow::Node subclassRef(DataFlow::TypeTracker t) { - t.start() and - result = views_attr("MethodView") - or - // subclasses in project code - result.asExpr().(ClassExpr).getABase() = subclassRef(t.continue()).asExpr() - or - exists(DataFlow::TypeTracker t2 | result = subclassRef(t2).track(t2, t)) - } - - /** Gets a reference to the `flask.views.View` class or any subclass. */ - DataFlow::Node subclassRef() { result = subclassRef(DataFlow::TypeTracker::end()) } + /** Gets a reference to the `flask.views.MethodView` class or any subclass. */ + API::Node subclassRef() { result = views().getMember("MethodView").getASubclass*() } } } } @@ -155,7 +128,7 @@ private module FlaskModel { private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { override CallNode node; - ClassInstantiation() { node.getFunction() = classRef().getAUse().asCfgNode() } + ClassInstantiation() { node = classRef().getACall().asCfgNode() } override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) } @@ -189,7 +162,12 @@ private module FlaskModel { // --------------------------------------------------------------------------- /** A flask View class defined in project code. */ class FlaskViewClassDef extends Class { - FlaskViewClassDef() { this.getABase() = flask::views::View::subclassRef().asExpr() } + API::Node api_node; + + FlaskViewClassDef() { + this.getABase() = flask::views::View::subclassRef().getAUse().asExpr() and + api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent() + } /** Gets a function that could handle incoming requests, if any. */ Function getARequestHandler() { @@ -199,42 +177,15 @@ private module FlaskModel { result.getName() = "dispatch_request" } - /** Gets a reference to this class. */ - private DataFlow::Node getARef(DataFlow::TypeTracker t) { - t.start() and - result.asExpr().(ClassExpr) = this.getParent() - or - exists(DataFlow::TypeTracker t2 | result = this.getARef(t2).track(t2, t)) - } - - /** Gets a reference to this class. */ - DataFlow::Node getARef() { result = this.getARef(DataFlow::TypeTracker::end()) } - - /** Gets a reference to the `as_view` classmethod of this class. */ - private DataFlow::Node asViewRef(DataFlow::TypeTracker t) { - t.startInAttr("as_view") and - result = this.getARef() - or - exists(DataFlow::TypeTracker t2 | result = this.asViewRef(t2).track(t2, t)) - } - - /** Gets a reference to the `as_view` classmethod of this class. */ - DataFlow::Node asViewRef() { result = this.asViewRef(DataFlow::TypeTracker::end()) } - /** Gets a reference to the result of calling the `as_view` classmethod of this class. */ - private DataFlow::Node asViewResult(DataFlow::TypeTracker t) { - t.start() and - result.asCfgNode().(CallNode).getFunction() = this.asViewRef().asCfgNode() - or - exists(DataFlow::TypeTracker t2 | result = asViewResult(t2).track(t2, t)) - } - - /** Gets a reference to the result of calling the `as_view` classmethod of this class. */ - DataFlow::Node asViewResult() { result = asViewResult(DataFlow::TypeTracker::end()) } + API::Node asViewResult() { result = api_node.getMember("as_view").getReturn() } } class FlaskMethodViewClassDef extends FlaskViewClassDef { - FlaskMethodViewClassDef() { this.getABase() = flask::views::MethodView::subclassRef().asExpr() } + FlaskMethodViewClassDef() { + this.getABase() = flask::views::MethodView::subclassRef().getAUse().asExpr() and + api_node.getAnImmediateUse().asExpr().(ClassExpr) = this.getParent() + } override Function getARequestHandler() { result = super.getARequestHandler() @@ -316,7 +267,7 @@ private module FlaskModel { ) or exists(FlaskViewClassDef vc | - getViewArg() = vc.asViewResult() and + getViewArg() = vc.asViewResult().getAUse() and result = vc.getARequestHandler() ) } From d3a79ecff16c85f4adf92c6326d02b1059b932c0 Mon Sep 17 00:00:00 2001 From: Taus Date: Fri, 5 Feb 2021 22:54:27 +0100 Subject: [PATCH 218/429] Update python/ql/src/semmle/python/frameworks/Flask.qll Co-authored-by: yoff --- python/ql/src/semmle/python/frameworks/Flask.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 178d089b2ea..3baa394ebcd 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -128,7 +128,7 @@ private module FlaskModel { private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { override CallNode node; - ClassInstantiation() { node = classRef().getACall().asCfgNode() } + ClassInstantiation() { this = classRef().getACall() } override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) } From 236b7c5887fc4809863a8303e81e14d2ef7efdad Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 5 Feb 2021 21:54:50 +0000 Subject: [PATCH 219/429] JS: Tolerate JSON in script tags --- .../semmle/js/extractor/HTMLExtractor.java | 5 ++- .../tests/html/input/json_in_script.html | 5 +++ .../html/output/trap/json_in_script.html.trap | 34 +++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 javascript/extractor/tests/html/input/json_in_script.html create mode 100644 javascript/extractor/tests/html/output/trap/json_in_script.html.trap diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index f18d3a8b337..561bbdb9171 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -331,7 +331,10 @@ public class HTMLExtractor implements IExtractor { textualExtractor.getMetrics(), textualExtractor.getExtractedFile()); Pair result = extractor.extract(tx, source, toplevelKind, scopeManager); - emitTopLevelXmlNodeBinding(parentHtmlNode, result.fst(), context, trapWriter); + Label toplevelLabel = result.fst(); + if (toplevelLabel != null) { // can be null when script ends up being parsed as JSON + emitTopLevelXmlNodeBinding(parentHtmlNode, toplevelLabel, context, trapWriter); + } locInfo.add(result.snd()); } catch (ParseError e) { e.setPosition(scriptLocationManager.translatePosition(e.getPosition())); diff --git a/javascript/extractor/tests/html/input/json_in_script.html b/javascript/extractor/tests/html/input/json_in_script.html new file mode 100644 index 00000000000..9c95c41c311 --- /dev/null +++ b/javascript/extractor/tests/html/input/json_in_script.html @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/javascript/extractor/tests/html/output/trap/json_in_script.html.trap b/javascript/extractor/tests/html/output/trap/json_in_script.html.trap new file mode 100644 index 00000000000..f7855255420 --- /dev/null +++ b/javascript/extractor/tests/html/output/trap/json_in_script.html.trap @@ -0,0 +1,34 @@ +#10000=@"/json_in_script.html;sourcefile" +files(#10000,"/json_in_script.html","json_in_script","html",0) +#10001=@"/;folder" +folders(#10001,"/","") +containerparent(#10001,#10000) +#10002=@"loc,{#10000},0,0,0,0" +locations_default(#10002,#10000,0,0,0,0) +hasLocation(#10000,#10002) +#20000=@"global_scope" +scopes(#20000,0) +#20001=* +json(#20001,5,#10000,0,"{""Hello"": 123}") +#20002=@"loc,{#10000},3,1,3,14" +locations_default(#20002,#10000,3,1,3,14) +json_locations(#20001,#20002) +#20003=* +json(#20003,2,#20001,0,"123") +#20004=@"loc,{#10000},3,11,3,13" +locations_default(#20004,#10000,3,11,3,13) +json_locations(#20003,#20004) +json_literals("123","123",#20003) +json_properties(#20001,"Hello",#20003) +#20005=* +xmlElements(#20005,"html",#10000,0,#10000) +#20006=@"loc,{#10000},1,1,5,7" +locations_default(#20006,#10000,1,1,5,7) +xmllocations(#20005,#20006) +#20007=* +xmlElements(#20007,"script",#20005,0,#10000) +#20008=@"loc,{#10000},2,1,4,9" +locations_default(#20008,#10000,2,1,4,9) +xmllocations(#20007,#20008) +numlines(#10000,5,0,0) +filetype(#10000,"html") From 0ceb8aa6380c9305f1f2905f9c5f87893eb13df1 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 5 Feb 2021 21:55:43 +0000 Subject: [PATCH 220/429] JS: Bump extractor version --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index fa4c138842a..b9fb9237556 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -43,7 +43,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2020-12-11"; + public static final String EXTRACTOR_VERSION = "2021-02-05"; public static final Pattern NEWLINE = Pattern.compile("\n"); From d775528069c33dd727a2c0f50a781b751047c693 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Fri, 5 Feb 2021 14:09:26 -0800 Subject: [PATCH 221/429] Fixes on multiple files. --- .../backdoor/DangerousNativeFunctionCall.qhelp | 4 ++-- .../backdoor/DangerousNativeFunctionCall.ql | 3 +-- .../Security Features/backdoor/PotentialTimeBomb.qhelp | 4 ++-- .../Security Features/backdoor/PotentialTimeBomb.ql | 2 +- .../backdoor/ProcessNameToHashTaintFlow.qhelp | 4 ++-- .../backdoor/ProcessNameToHashTaintFlow.ql | 7 +++---- .../Solorigate/ModifiedFnvFunctionDetection.qhelp | 4 ++-- .../Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp | 4 ++-- .../Solorigate/NumberOfKnownHashesAboveThreshold.ql | 8 ++++---- .../Solorigate/NumberOfKnownLiteralsAboveThreshold.ql | 4 ++-- .../Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql | 2 +- .../campaign/Solorigate/Solorigate.qhelp | 2 +- .../Solorigate/SwallowEverythingExceptionHandler.qhelp | 2 +- 13 files changed, 24 insertions(+), 26 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp index 75bd300601e..f499eebfdbf 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qhelp @@ -3,11 +3,11 @@ "qhelp.dtd"> -

    This query finds native calls to external functions that are often used in creating backdoors or are generally attributed to unsafe code practices.

    +

    This query finds native calls to external functions that are often used in creating backdoors or are generally attributed to unsafe code practices. This is an example of a query that may be useful for detecting potential backdoors. Solorigate is one example that uses this mechanism.

    -

    Any findings from this rules is only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack, but no certainty that the code is related or part of any attack.

    +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    diff --git a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql index af1500fb215..c9d247d69f3 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql @@ -1,7 +1,6 @@ /** * @name Potential dangerous use of native functions - * @description Please review code for possible malicious intent or unsafe handling. - * NOTE: This query is an example of a query that may be useful for detecting potential backdoors, and Solorigate is just one such example that uses this mechanism. + * @description Detects the use of native functions that can be used for malicious intent or unsafe handling. * @kind problem * @problem.severity warning * @precision low diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp index c9cecee8374..fb619cb738e 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp @@ -3,11 +3,11 @@ "qhelp.dtd"> -

    This query finds if there exists a DataFlow from a file last modification date (very likely implant installation time) and an offset to a condition statement (the trigger) that controls code execution.

    +

    This query checks for data flow from a file's last modification date and a condition statement that controls code execution. A malicious actor could have implanted code that triggers after a certain time, leading to a "time bomb".

    -

    Any findings from this rules is only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack, but no certainty that the code is related or part of any attack.

    +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql index 332df2d2a28..31c00e8a378 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql @@ -1,6 +1,6 @@ /** * @name Potential Timebomb - * @description Flow from a file last modification date (very likely implant installation time) and an offset to condition statement (the trigger) + * @description If there is data flow from a file's last modification date and an offset to a condition statement, this could trigger a "time bomb". * @kind path-problem * @precision Low * @problem.severity warning diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp index 12eb83191ac..cb1faf86974 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qhelp @@ -4,11 +4,11 @@

    This query detects code flow from ProcessName property on the Process class into a hash function.

    -

    Such flow is often used in code backdoors to detect runnig processes and compare them to an obfuscated list of antivirus processes to aviod detection.

    +

    Such flow is often used in code backdoors to detect running processes and compare them to an obfuscated list of antivirus processes to avoid detection. Solorigate is one example that uses this mechanism.

    -

    Any findings from this rules is only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack, but no certainty that the code is related or part of any attack.

    +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    For more information about Solorigate, please visit https://aka.ms/solorigate.

    diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql index 96363bbadff..d6fd090540e 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -1,7 +1,6 @@ /** * @name ProcessName to hash function flow - * @description Flow from a function retrieving process name to a hash function - * NOTE: This query is an example of a query that may be useful for detecting potential backdoors, and Solorigate is just one such example that uses this mechanism. + * @description Flow from a function retrieving process name to a hash function. * @kind path-problem * @tags security * solorigate @@ -20,12 +19,12 @@ class DataFlowFromMethodToHash extends TaintTracking::Configuration { /** * Holds if `source` is a relevant data flow source. */ - override predicate isSource(Node source) { isSuspiciousPropertyName(source.asExpr()) } + override predicate isSource(DataFlow::Node source) { isSuspiciousPropertyName(source.asExpr()) } /** * Holds if `sink` is a relevant data flow sink. */ - override predicate isSink(Node sink) { isGetHash(sink.asExpr()) } + override predicate isSink(DataFlow::Node sink) { isGetHash(sink.asExpr()) } } predicate isGetHash(Expr arg) { diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp index ffa32c5937d..8b639b14ab0 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp @@ -3,8 +3,8 @@ "qhelp.dtd"> -

    The malicious code included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by a literal after computing the FNV-1A.

    -

    This query detects FNV-like hash calculations where there is an additional xor (with any static value) after the hash calculation loop.

    +

    In Solorigate, the malicious code tried to evade various security detection software by comparing hashes of the process names against an embedded list of values. The malicious code included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by a literal after computing the FNV-1A.

    +

    This query detects FNV-like hash calculations where there is an additional XOR (with any static value) after the hash calculation loop.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp index 0db1732805d..9417cbb2645 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp @@ -3,8 +3,8 @@ "qhelp.dtd"> -

    This query detects if there is an enum that includes various of the values used for the Solorigate commands.

    -

    Please notice that by themselves the names of these enum constants are not malign.

    +

    This query detects enumerations that include various commands that were also used in the Solorigate implant.

    +

    By themselves, the names of these enumeration constants are not malicious, so the query only detects enumerations that includes at least 10 of the 18 Solorigate commands.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql index 392a0d97165..541f3205c01 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql @@ -1,7 +1,7 @@ /** - * @name Number of Solorigate-related Hashes as literals is above the threshold - * @description The total number of Solorigate-related hash literals found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. - * It is recommended to review the code and verify that there is no unexpected code in this project, however it is highly unlikely the hash values would be present coincideentally + * @name Number of Solorigate-related hashes as literals is above the threshold + * @description The total number of Solorigate-related hash literals found in the code is above a threshold, which may indicate that an external agent has tampered with the code. + * It is recommended to review the code and verify that there is no unexpected code in this project, however it is highly unlikely the hash values would be present coincidentally. * @kind problem * @tags security * solorigate @@ -14,7 +14,7 @@ import csharp import Solorigate /* - * Returns the total number of Solorigate-related literales found in the project + * Returns the total number of Solorigate-related hashes found in the project */ int countSolorigateSuspiciousHash() { diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql index 2055dda9946..a18f0c40916 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql @@ -1,6 +1,6 @@ /** * @name Number of Solorigate-related literals is above the threshold - * @description The total number of Solorigate-related literals found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. + * @description The total number of Solorigate-related literals found in the code is above a threshold, which may indicate that an external agent has tampered with the code. * It is recommended to review the code and verify that there is no unexpected code in this project. * @kind problem * @tags security @@ -14,7 +14,7 @@ import csharp import Solorigate /* - * Returns the total number of Solorigate-related literales found in the project + * Returns the total number of Solorigate-related literals found in the project */ int countSolorigateSuspiciousLiterals() { diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql index a3bac88cb78..c60281882b8 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql @@ -1,6 +1,6 @@ /** * @name Number of Solorigate-related method names is above the threshold - * @description The total number of Solorigate-related method names found in the code is above a threshold, which may indicate that the code may have been tampered by an external agent. + * @description The total number of Solorigate-related method names found in the code is above a threshold, which may indicate that an external agent has tampered with the code. * It is recommended to review the code and verify that there is no unexpected code in this project. * @kind problem * @tags security diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp index 19c5c2666cd..dcd7c0b9d74 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp @@ -7,7 +7,7 @@

    The purpose of these rules is to identify potentially tampered code that requires further analysis

    -

    Any findings from these rules are only intended to indicate suspicious code that shares similarities with known portions of code used for this attack, but no certainty that the code is related or part of any attack.

    +

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    For more information, please visit https://aka.ms/solorigate.

    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp index 83fa8f8c58c..7be5a1f902e 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp @@ -3,7 +3,7 @@ "qhelp.dtd"> -

    The malicious code was wrapped in generic exception catch blocks that lacked any statements

    +

    In Solorigate, the malicious code was wrapped in generic exception catch blocks that lacked any statements. This made it harder to find any suspicious runtime exceptions.

    This query detects all generic exception empty catch blocks, but it is strongly suggested that the results for cs/catch-of-all-exceptions also be reviewed in the event that a malicious swallow everything exception handler was not empty

    From ddd362bc16eaf0049aeda6fc5e7204982404008a Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 5 Feb 2021 23:31:20 +0100 Subject: [PATCH 222/429] Update python/ql/src/semmle/python/frameworks/Django.qll Co-authored-by: Rasmus Wriedt Larsen --- python/ql/src/semmle/python/frameworks/Django.qll | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 3832f5c410e..fd43d938806 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2314,6 +2314,13 @@ private module Django { DjangoShortcutsRedirectCall() { node.getFunction() = django::shortcuts::redirect().asCfgNode() } + /** + * Gets the data-flow node that specifies the location of this HTTP redirect response. + * + * Note: For `django.shortcuts.redirect`, the result might not be a full URL + * (as usually expected by this method), but could be a relative URL, + * a string identifying a view, or a Django model. + */ override DataFlow::Node getRedirectLocation() { result.asCfgNode() in [node.getArg(0), node.getArgByName("to")] } From 7c506f445ce8597cdd3bd66df777c49d93e19785 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 6 Nov 2020 13:02:41 +0100 Subject: [PATCH 223/429] C#: Extract underlying methods of foreach statements --- .../2021-02-02-foreach-underlying-methods.md | 3 + .../Entities/Statements/ForEach.cs | 14 ++- .../Semmle.Extraction.CSharp/Tuples.cs | 6 + csharp/ql/src/Dead Code/DeadCode.qll | 2 + .../raw/internal/desugar/Foreach.qll | 39 +------ csharp/ql/src/semmle/code/csharp/Stmt.qll | 21 ++++ csharp/ql/src/semmlecode.csharp.dbscheme | 9 ++ .../library-tests/csharp9/ForeachExtension.cs | 50 +++++++++ .../library-tests/csharp9/PrintAst.expected | 103 ++++++++++++++++++ .../library-tests/csharp9/foreach.expected | 4 + .../ql/test/library-tests/csharp9/foreach.ql | 15 +++ .../csharp9/typeParameterNullability.expected | 2 - .../csharp9/typeParameterNullability.ql | 6 +- csharp/upgrades/TO_CHANGE/upgrade.properties | 2 + 14 files changed, 235 insertions(+), 41 deletions(-) create mode 100644 csharp/change-notes/2021-02-02-foreach-underlying-methods.md create mode 100644 csharp/ql/test/library-tests/csharp9/ForeachExtension.cs create mode 100644 csharp/ql/test/library-tests/csharp9/foreach.expected create mode 100644 csharp/ql/test/library-tests/csharp9/foreach.ql create mode 100644 csharp/upgrades/TO_CHANGE/upgrade.properties diff --git a/csharp/change-notes/2021-02-02-foreach-underlying-methods.md b/csharp/change-notes/2021-02-02-foreach-underlying-methods.md new file mode 100644 index 00000000000..a9e934a0e5d --- /dev/null +++ b/csharp/change-notes/2021-02-02-foreach-underlying-methods.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The underlying methods of `foreach` statements are now explicitly extracted and +they are made available on the `ForeachStmt` class. diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 262b3f0e328..ebd0f301b42 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -18,11 +18,12 @@ namespace Semmle.Extraction.CSharp.Entities.Statements return ret; } - protected override void PopulateStatement(TextWriter _) + protected override void PopulateStatement(TextWriter trapFile) { Expression.Create(cx, Stmt.Expression, this, 1); - var typeSymbol = cx.GetModel(Stmt).GetDeclaredSymbol(Stmt); + var semanticModel = cx.GetModel(Stmt); + var typeSymbol = semanticModel.GetDeclaredSymbol(Stmt); var type = typeSymbol.GetAnnotatedType(); var location = cx.Create(Stmt.Identifier.GetLocation()); @@ -30,6 +31,15 @@ namespace Semmle.Extraction.CSharp.Entities.Statements Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0); Statement.Create(cx, Stmt.Statement, this, 2); + + var info = semanticModel.GetForEachStatementInfo(Stmt); + var getEnumerator = Method.Create(cx, info.GetEnumeratorMethod); + var currentProp = Property.Create(cx, info.CurrentProperty); + var moveNext = Method.Create(cx, info.MoveNextMethod); + var dispose = Method.Create(cx, info.DisposeMethod); + var elementType = Type.Create(cx, info.ElementType); + + trapFile.foreach_stmt_info(this, elementType, getEnumerator, moveNext, dispose, currentProp, info.IsAsynchronous); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index ec2bd66d32e..cfb797f6ff7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -53,6 +53,12 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("catch_type", @catch, type, explicityCaught ? 1 : 2); } + internal static void foreach_stmt_info(this TextWriter trapFile, Entities.Statements.ForEach @foreach, Type element, Method getEnumerator, + Method moveNext, Method dispose, Property current, bool isAsync) + { + trapFile.WriteTuple("foreach_stmt_info", @foreach, element, getEnumerator, moveNext, dispose, current, isAsync ? 2 : 1); + } + internal static void commentblock(this TextWriter trapFile, CommentBlock k) { trapFile.WriteTuple("commentblock", k); diff --git a/csharp/ql/src/Dead Code/DeadCode.qll b/csharp/ql/src/Dead Code/DeadCode.qll index e3584eaa1a4..efb7a76ee78 100644 --- a/csharp/ql/src/Dead Code/DeadCode.qll +++ b/csharp/ql/src/Dead Code/DeadCode.qll @@ -43,6 +43,8 @@ Expr getAMethodAccess(Method m) { predicate potentiallyAccessedByForEach(Method m) { m.hasName("GetEnumerator") and m.getDeclaringType().getABaseType+().hasQualifiedName("System.Collections.IEnumerable") + or + foreach_stmt_info(_, _, m, _, _, _, _) } predicate isRecursivelyLiveExpression(Expr e) { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll index 9dee8221235..a526ec5bdcd 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/desugar/Foreach.qll @@ -171,11 +171,7 @@ private class TranslatedForeachMoveNext extends TranslatedCompilerGeneratedCall, override Callable getInstructionFunction(InstructionTag tag) { tag = CallTargetTag() and - exists(Callable internal | - internal.getName() = "MoveNext" and - internal.getReturnType() instanceof BoolType and - result = internal - ) + result = generatedBy.getMoveNext() } override Type getCallResultType() { result instanceof BoolType } @@ -205,28 +201,9 @@ private class TranslatedForeachGetEnumerator extends TranslatedCompilerGenerated result = getInstructionFunction(CallTargetTag()).getReturnType() } - private Callable getEnumeratorCallable() { - if exists(generatedBy.getIterableExpr().getType().(ValueOrRefType).getAMember("GetEnumerator")) - then - result = generatedBy.getIterableExpr().getType().(ValueOrRefType).getAMember("GetEnumerator") - else - exists(Interface inter | - inter = - generatedBy - .getIterableExpr() - .getType() - .(ValueOrRefType) - // There could be some abstract base types until we reach `IEnumerable` (eg. `Array`) - .getABaseType*() - .getABaseInterface() and - inter.getName() = "IEnumerable" and - result = inter.getAMember("GetEnumerator") - ) - } - override Callable getInstructionFunction(InstructionTag tag) { tag = CallTargetTag() and - result = getEnumeratorCallable() + result = generatedBy.getGetEnumerator() } override TranslatedExpr getArgument(int id) { none() } @@ -247,7 +224,7 @@ private class TranslatedForeachCurrent extends TranslatedCompilerGeneratedCall, TranslatedForeachCurrent() { this = TTranslatedCompilerGeneratedElement(generatedBy, 5) } - override Type getCallResultType() { result = generatedBy.getAVariable().getType() } + override Type getCallResultType() { result = generatedBy.getElementType() } override TranslatedExpr getArgument(int id) { none() } @@ -262,10 +239,7 @@ private class TranslatedForeachCurrent extends TranslatedCompilerGeneratedCall, override Callable getInstructionFunction(InstructionTag tag) { tag = CallTargetTag() and - exists(Property prop | - prop.getName() = "Current" and - result = prop.getGetter() - ) + result = generatedBy.getCurrent().getGetter() } } @@ -280,10 +254,7 @@ private class TranslatedForeachDispose extends TranslatedCompilerGeneratedCall, override Callable getInstructionFunction(InstructionTag tag) { tag = CallTargetTag() and - exists(Callable dispose | - dispose.getName() = "Dispose" and - result = dispose - ) + result = generatedBy.getDispose() } final override Type getCallResultType() { result instanceof VoidType } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 8fadbc1267b..68e26ff0a8c 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -582,6 +582,27 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { */ Expr getIterableExpr() { result = this.getChild(1) } + /** Gets the called `GetEnumerator` method. */ + Method getGetEnumerator() { foreach_stmt_info(this, _, result, _, _, _, _) } + + /** Gets the called `MoveNext` or `MoveNextAsync` method. */ + Method getMoveNext() { foreach_stmt_info(this, _, _, result, _, _, _) } + + /** Gets the called `Dispose` or `DisposeAsync` method. */ + Method getDispose() { foreach_stmt_info(this, _, _, _, result, _, _) } + + /** Gets the called `Current` property. */ + Property getCurrent() { foreach_stmt_info(this, _, _, _, _, result, _) } + + /** + * Gets the intermediate type to which the `Current` property is converted before + * being converted to the iteration variable type. + */ + Type getElementType() { foreach_stmt_info(this, result, _, _, _, _, _) } + + /** Holds if this `foreach` statement is asynchronous. */ + predicate isAsync() { foreach_stmt_info(this, _, _, _, _, _, 2) } + override string toString() { result = "foreach (... ... in ...) ..." } override string getAPrimaryQlClass() { result = "ForeachStmt" } diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 68db341c2ed..bcfb223217d 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -982,6 +982,15 @@ catch_type( int type_id: @type_or_ref ref, int kind: int ref /* explicit = 1, implicit = 2 */); +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int element_type_id: @type_or_ref ref, + int getenumerator_id: @method ref, + int movenext_id: @method ref, + int dispose_id: @method ref, + int current_id: @property ref, + int kind: int ref /* non-async = 1, async = 2 */); + /** EXPRESSIONS **/ expressions( diff --git a/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs b/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs new file mode 100644 index 00000000000..0ef36fbc7d9 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +static class Extensions +{ + public static IEnumerator GetEnumerator(this IEnumerator enumerator) => enumerator; + public static IAsyncEnumerator GetAsyncEnumerator(this IAsyncEnumerator enumerator) => enumerator; + public static IEnumerator GetEnumerator(this int count) + { + for (int i = 0; i < count; i++) + { + yield return i; + } + } +} + +class Program +{ + async Task Main() + { + IEnumerator enumerator1 = Enumerable.Range(0, 10).GetEnumerator(); + foreach (var item in enumerator1) + { + } + + IAsyncEnumerator enumerator2 = GetAsyncEnumerator(); + await foreach (var item in enumerator2) + { + } + + foreach (var item in 42) + { + } + + foreach (var i in new int[] { 1, 2, 3 }) // not extension + { + } + } + + static async IAsyncEnumerator GetAsyncEnumerator() + { + yield return 0; + await Task.Delay(1); + yield return 1; + } +} + +// semmle-extractor-options: /r:System.Linq.dll \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index ea3540ce4ce..e203842664b 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -166,6 +166,109 @@ Discard.cs: # 10| 4: [BlockStmt] {...} # 10| 0: [ReturnStmt] return ...; # 10| 0: [IntLiteral] 0 +ForeachExtension.cs: +# 6| [Class] Extensions +# 8| 4: [ExtensionMethod] GetEnumerator +# 8| -1: [TypeMention] IEnumerator +# 8| 1: [TypeMention] T +#-----| 1: (Type parameters) +# 8| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 8| 0: [Parameter] enumerator +# 8| -1: [TypeMention] IEnumerator +# 8| 1: [TypeMention] T +# 8| 4: [ParameterAccess] access to parameter enumerator +# 9| 6: [ExtensionMethod] GetAsyncEnumerator +# 9| -1: [TypeMention] IAsyncEnumerator +# 9| 1: [TypeMention] T +#-----| 1: (Type parameters) +# 9| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 9| 0: [Parameter] enumerator +# 9| -1: [TypeMention] IAsyncEnumerator +# 9| 1: [TypeMention] T +# 9| 4: [ParameterAccess] access to parameter enumerator +# 10| 8: [ExtensionMethod] GetEnumerator +# 10| -1: [TypeMention] IEnumerator +# 10| 1: [TypeMention] int +#-----| 2: (Parameters) +# 10| 0: [Parameter] count +# 10| -1: [TypeMention] int +# 11| 4: [BlockStmt] {...} +# 12| 0: [ForStmt] for (...;...;...) ... +# 12| -1: [LocalVariableDeclAndInitExpr] Int32 i = ... +# 12| -1: [TypeMention] int +# 12| 0: [LocalVariableAccess] access to local variable i +# 12| 1: [IntLiteral] 0 +# 12| 0: [LTExpr] ... < ... +# 12| 0: [LocalVariableAccess] access to local variable i +# 12| 1: [ParameterAccess] access to parameter count +# 12| 1: [PostIncrExpr] ...++ +# 12| 0: [LocalVariableAccess] access to local variable i +# 13| 2: [BlockStmt] {...} +# 14| 0: [YieldReturnStmt] yield return ...; +# 14| 0: [LocalVariableAccess] access to local variable i +# 19| [Class] Program +# 21| 5: [Method] Main +# 21| -1: [TypeMention] Task +# 22| 4: [BlockStmt] {...} +# 23| 0: [LocalVariableDeclStmt] ... ...; +# 23| 0: [LocalVariableDeclAndInitExpr] IEnumerator enumerator1 = ... +# 23| -1: [TypeMention] IEnumerator +# 23| 1: [TypeMention] int +# 23| 0: [LocalVariableAccess] access to local variable enumerator1 +# 23| 1: [MethodCall] call to method GetEnumerator +# 23| -1: [MethodCall] call to method Range +# 23| -1: [TypeAccess] access to type Enumerable +# 23| 0: [TypeMention] Enumerable +# 23| 0: [IntLiteral] 0 +# 23| 1: [IntLiteral] 10 +# 24| 1: [ForeachStmt] foreach (... ... in ...) ... +# 24| 0: [LocalVariableDeclExpr] Int32 item +# 24| 0: [TypeMention] int +# 24| 1: [LocalVariableAccess] access to local variable enumerator1 +# 25| 2: [BlockStmt] {...} +# 28| 2: [LocalVariableDeclStmt] ... ...; +# 28| 0: [LocalVariableDeclAndInitExpr] IAsyncEnumerator enumerator2 = ... +# 28| -1: [TypeMention] IAsyncEnumerator +# 28| 1: [TypeMention] int +# 28| 0: [LocalVariableAccess] access to local variable enumerator2 +# 28| 1: [MethodCall] call to method GetAsyncEnumerator +# 29| 3: [ForeachStmt] foreach (... ... in ...) ... +# 29| 0: [LocalVariableDeclExpr] Int32 item +# 29| 0: [TypeMention] int +# 29| 1: [LocalVariableAccess] access to local variable enumerator2 +# 30| 2: [BlockStmt] {...} +# 33| 4: [ForeachStmt] foreach (... ... in ...) ... +# 33| 0: [LocalVariableDeclExpr] Int32 item +# 33| 0: [TypeMention] int +# 33| 1: [IntLiteral] 42 +# 34| 2: [BlockStmt] {...} +# 37| 5: [ForeachStmt] foreach (... ... in ...) ... +# 37| 0: [LocalVariableDeclExpr] Int32 i +# 37| 0: [TypeMention] int +# 37| 1: [ArrayCreation] array creation of type Int32[] +# 37| -2: [TypeMention] Int32[] +# 37| 1: [TypeMention] int +# 37| -1: [ArrayInitializer] { ..., ... } +# 37| 0: [IntLiteral] 1 +# 37| 1: [IntLiteral] 2 +# 37| 2: [IntLiteral] 3 +# 38| 2: [BlockStmt] {...} +# 42| 6: [Method] GetAsyncEnumerator +# 42| -1: [TypeMention] IAsyncEnumerator +# 42| 1: [TypeMention] int +# 43| 4: [BlockStmt] {...} +# 44| 0: [YieldReturnStmt] yield return ...; +# 44| 0: [IntLiteral] 0 +# 45| 1: [ExprStmt] ...; +# 45| 0: [AwaitExpr] await ... +# 45| 0: [MethodCall] call to method Delay +# 45| -1: [TypeAccess] access to type Task +# 45| 0: [TypeMention] Task +# 45| 0: [IntLiteral] 1 +# 46| 2: [YieldReturnStmt] yield return ...; +# 46| 0: [IntLiteral] 1 FunctionPointer.cs: # 5| [Class] FnPointer # 7| 5: [Class] Program diff --git a/csharp/ql/test/library-tests/csharp9/foreach.expected b/csharp/ql/test/library-tests/csharp9/foreach.expected new file mode 100644 index 00000000000..39694665cb0 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/foreach.expected @@ -0,0 +1,4 @@ +| ForeachExtension.cs:24:9:26:9 | foreach (... ... in ...) ... | Int32 | sync | Extensions | ForeachExtension.cs:8:34:8:49 | System.Collections.Generic.IEnumerator | - | System.Collections.IEnumerator | - | +| ForeachExtension.cs:29:9:31:9 | foreach (... ... in ...) ... | Int32 | async | Extensions | ForeachExtension.cs:9:39:9:59 | System.Collections.Generic.IAsyncEnumerator | - | System.Collections.Generic.IAsyncEnumerator | - | +| ForeachExtension.cs:33:9:35:9 | foreach (... ... in ...) ... | Int32 | sync | Extensions | ForeachExtension.cs:10:36:10:48 | System.Collections.Generic.IEnumerator | - | System.Collections.IEnumerator | - | +| ForeachExtension.cs:37:9:39:9 | foreach (... ... in ...) ... | Int32 | sync | System.Collections.IEnumerable | - | System.Collections.IEnumerator | - | System.Collections.IEnumerator | - | diff --git a/csharp/ql/test/library-tests/csharp9/foreach.ql b/csharp/ql/test/library-tests/csharp9/foreach.ql new file mode 100644 index 00000000000..38d431d762f --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/foreach.ql @@ -0,0 +1,15 @@ +import csharp + +private string getLocation(Member m) { + if m.fromSource() then result = m.getALocation().(SourceLocation).toString() else result = "-" +} + +private string getIsAsync(ForeachStmt f) { + if f.isAsync() then result = "async" else result = "sync" +} + +from ForeachStmt f +select f, f.getElementType().toString(), getIsAsync(f), + f.getGetEnumerator().getDeclaringType().getQualifiedName(), getLocation(f.getGetEnumerator()), + f.getCurrent().getDeclaringType().getQualifiedName(), getLocation(f.getCurrent()), + f.getMoveNext().getDeclaringType().getQualifiedName(), getLocation(f.getMoveNext()) diff --git a/csharp/ql/test/library-tests/csharp9/typeParameterNullability.expected b/csharp/ql/test/library-tests/csharp9/typeParameterNullability.expected index cd42090259a..cfec2a5ca11 100644 --- a/csharp/ql/test/library-tests/csharp9/typeParameterNullability.expected +++ b/csharp/ql/test/library-tests/csharp9/typeParameterNullability.expected @@ -10,8 +10,6 @@ valueType | TypeParameterNullability.cs:19:29:19:29 | T | | TypeParameterNullability.cs:24:29:24:29 | T | valueOrRefType -| FunctionPointer.cs:22:24:22:24 | T | -| FunctionPointer.cs:34:24:34:24 | T | | TypeParameterNullability.cs:5:28:5:28 | T | | TypeParameterNullability.cs:9:28:9:28 | T | | TypeParameterNullability.cs:15:29:15:29 | T | diff --git a/csharp/ql/test/library-tests/csharp9/typeParameterNullability.ql b/csharp/ql/test/library-tests/csharp9/typeParameterNullability.ql index 58d3bfb8fb9..d8a966e2ff2 100644 --- a/csharp/ql/test/library-tests/csharp9/typeParameterNullability.ql +++ b/csharp/ql/test/library-tests/csharp9/typeParameterNullability.ql @@ -1,17 +1,17 @@ import csharp query predicate refType(TypeParameter tp) { - tp.fromSource() and + tp.getFile().getStem() = "TypeParameterNullability" and tp.isRefType() } query predicate valueType(TypeParameter tp) { - tp.fromSource() and + tp.getFile().getStem() = "TypeParameterNullability" and tp.isValueType() } query predicate valueOrRefType(TypeParameter tp) { - tp.fromSource() and + tp.getFile().getStem() = "TypeParameterNullability" and not tp.isRefType() and not tp.isValueType() } diff --git a/csharp/upgrades/TO_CHANGE/upgrade.properties b/csharp/upgrades/TO_CHANGE/upgrade.properties new file mode 100644 index 00000000000..f9cd85e1661 --- /dev/null +++ b/csharp/upgrades/TO_CHANGE/upgrade.properties @@ -0,0 +1,2 @@ +description: Add 'foreach_stmt_info' relation. +compatibility: backwards \ No newline at end of file From 63b0fe10e428a28c47dd8954d6370384007a3e5d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 4 Feb 2021 11:19:05 +0100 Subject: [PATCH 224/429] Rework foreach_stmt_info extraction --- .../Entities/Statements/ForEach.cs | 52 ++++++++++++++++--- .../Semmle.Extraction.CSharp/Tuples.cs | 11 ++-- csharp/ql/src/Dead Code/DeadCode.qll | 2 +- csharp/ql/src/semmle/code/csharp/Stmt.qll | 12 ++--- csharp/ql/src/semmlecode.csharp.dbscheme | 13 +++-- csharp/upgrades/TO_CHANGE/upgrade.properties | 2 +- 6 files changed, 70 insertions(+), 22 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index ebd0f301b42..6696086b19c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -8,6 +8,15 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal class ForEach : Statement { + internal enum ForeachSymbolType + { + GetEnumeratorMethod = 1, + CurrentProperty, + MoveNextMethod, + DisposeMethod, + ElementType + } + private ForEach(Context cx, ForEachStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.FOREACH, parent, child) { } @@ -33,13 +42,44 @@ namespace Semmle.Extraction.CSharp.Entities.Statements Statement.Create(cx, Stmt.Statement, this, 2); var info = semanticModel.GetForEachStatementInfo(Stmt); - var getEnumerator = Method.Create(cx, info.GetEnumeratorMethod); - var currentProp = Property.Create(cx, info.CurrentProperty); - var moveNext = Method.Create(cx, info.MoveNextMethod); - var dispose = Method.Create(cx, info.DisposeMethod); - var elementType = Type.Create(cx, info.ElementType); - trapFile.foreach_stmt_info(this, elementType, getEnumerator, moveNext, dispose, currentProp, info.IsAsynchronous); + if (info.Equals(default)) + { + cx.ExtractionError("Could not get foreach statement info", null, Location.Create(cx, this.ReportingLocation), severity: Util.Logging.Severity.Info); + return; + } + + trapFile.foreach_stmt_info(this, info.IsAsynchronous); + + if (info.GetEnumeratorMethod != null) + { + var m = Method.Create(cx, info.GetEnumeratorMethod); + trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.GetEnumeratorMethod); + } + + if (info.MoveNextMethod != null) + { + var m = Method.Create(cx, info.MoveNextMethod); + trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.MoveNextMethod); + } + + if (info.DisposeMethod != null) + { + var m = Method.Create(cx, info.DisposeMethod); + trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.DisposeMethod); + } + + if (info.CurrentProperty != null) + { + var p = Property.Create(cx, info.CurrentProperty); + trapFile.foreach_stmt_desugar(this, p, ForeachSymbolType.CurrentProperty); + } + + if (info.ElementType != null) + { + var t = Type.Create(cx, info.ElementType); + trapFile.foreach_stmt_desugar(this, t, ForeachSymbolType.ElementType); + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index cfb797f6ff7..df39d6a836c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -53,10 +53,15 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("catch_type", @catch, type, explicityCaught ? 1 : 2); } - internal static void foreach_stmt_info(this TextWriter trapFile, Entities.Statements.ForEach @foreach, Type element, Method getEnumerator, - Method moveNext, Method dispose, Property current, bool isAsync) + internal static void foreach_stmt_info(this TextWriter trapFile, Entities.Statements.ForEach @foreach, bool isAsync) { - trapFile.WriteTuple("foreach_stmt_info", @foreach, element, getEnumerator, moveNext, dispose, current, isAsync ? 2 : 1); + trapFile.WriteTuple("foreach_stmt_info", @foreach, isAsync ? 2 : 1); + } + + internal static void foreach_stmt_desugar(this TextWriter trapFile, Entities.Statements.ForEach @foreach, IEntity entity, + Entities.Statements.ForEach.ForeachSymbolType type) + { + trapFile.WriteTuple("foreach_stmt_desugar", @foreach, entity, (int)type); } internal static void commentblock(this TextWriter trapFile, CommentBlock k) diff --git a/csharp/ql/src/Dead Code/DeadCode.qll b/csharp/ql/src/Dead Code/DeadCode.qll index efb7a76ee78..dd0f6104e31 100644 --- a/csharp/ql/src/Dead Code/DeadCode.qll +++ b/csharp/ql/src/Dead Code/DeadCode.qll @@ -44,7 +44,7 @@ predicate potentiallyAccessedByForEach(Method m) { m.hasName("GetEnumerator") and m.getDeclaringType().getABaseType+().hasQualifiedName("System.Collections.IEnumerable") or - foreach_stmt_info(_, _, m, _, _, _, _) + foreach_stmt_desugar(_, m, 1) } predicate isRecursivelyLiveExpression(Expr e) { diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 68e26ff0a8c..2846c3255ea 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -583,25 +583,25 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { Expr getIterableExpr() { result = this.getChild(1) } /** Gets the called `GetEnumerator` method. */ - Method getGetEnumerator() { foreach_stmt_info(this, _, result, _, _, _, _) } + Method getGetEnumerator() { foreach_stmt_desugar(this, result, 1) } /** Gets the called `MoveNext` or `MoveNextAsync` method. */ - Method getMoveNext() { foreach_stmt_info(this, _, _, result, _, _, _) } + Method getMoveNext() { foreach_stmt_desugar(this, result, 3) } /** Gets the called `Dispose` or `DisposeAsync` method. */ - Method getDispose() { foreach_stmt_info(this, _, _, _, result, _, _) } + Method getDispose() { foreach_stmt_desugar(this, result, 4) } /** Gets the called `Current` property. */ - Property getCurrent() { foreach_stmt_info(this, _, _, _, _, result, _) } + Property getCurrent() { foreach_stmt_desugar(this, result, 2) } /** * Gets the intermediate type to which the `Current` property is converted before * being converted to the iteration variable type. */ - Type getElementType() { foreach_stmt_info(this, result, _, _, _, _, _) } + Type getElementType() { foreach_stmt_desugar(this, result, 5) } /** Holds if this `foreach` statement is asynchronous. */ - predicate isAsync() { foreach_stmt_info(this, _, _, _, _, _, 2) } + predicate isAsync() { foreach_stmt_info(this, 2) } override string toString() { result = "foreach (... ... in ...) ..." } diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index bcfb223217d..16936565fbe 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -984,13 +984,16 @@ catch_type( foreach_stmt_info( unique int id: @foreach_stmt ref, - int element_type_id: @type_or_ref ref, - int getenumerator_id: @method ref, - int movenext_id: @method ref, - int dispose_id: @method ref, - int current_id: @property ref, int kind: int ref /* non-async = 1, async = 2 */); +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + /** EXPRESSIONS **/ expressions( diff --git a/csharp/upgrades/TO_CHANGE/upgrade.properties b/csharp/upgrades/TO_CHANGE/upgrade.properties index f9cd85e1661..0b0c3a88460 100644 --- a/csharp/upgrades/TO_CHANGE/upgrade.properties +++ b/csharp/upgrades/TO_CHANGE/upgrade.properties @@ -1,2 +1,2 @@ -description: Add 'foreach_stmt_info' relation. +description: Add 'foreach_stmt_info' and 'foreach_stmt_desugar' relations. compatibility: backwards \ No newline at end of file From 96248f88458b9469ca0de72839cfb4cf5d0e8715 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 5 Feb 2021 09:23:22 +0100 Subject: [PATCH 225/429] Add DB upgrade folder --- .../old.dbscheme | 2070 ++++++++++++++++ .../semmlecode.csharp.dbscheme | 2082 +++++++++++++++++ .../upgrade.properties | 0 3 files changed, 4152 insertions(+) create mode 100644 csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/old.dbscheme create mode 100644 csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/semmlecode.csharp.dbscheme rename csharp/upgrades/{TO_CHANGE => 68db341c2ed1693c2ae6e20ad533c84138cb275a}/upgrade.properties (100%) diff --git a/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/old.dbscheme b/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/old.dbscheme new file mode 100644 index 00000000000..68db341c2ed --- /dev/null +++ b/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/old.dbscheme @@ -0,0 +1,2070 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_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 + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file 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 +); + +diagnostics( + unique int id: @diagnostic, + 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 +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string 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`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +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); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +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); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref +) + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/semmlecode.csharp.dbscheme b/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/semmlecode.csharp.dbscheme new file mode 100644 index 00000000000..16936565fbe --- /dev/null +++ b/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/semmlecode.csharp.dbscheme @@ -0,0 +1,2082 @@ + +/** + * An invocation of the compiler. Note that more than one file may be + * compiled per invocation. For example, this command compiles three + * source files: + * + * csc f1.cs f2.cs f3.cs + * + * The `id` simply identifies the invocation, while `cwd` is the working + * directory from which the compiler was invoked. + */ +compilations( + unique int id : @compilation, + string cwd : string ref +); + +/** + * The arguments that were passed to the extractor for a compiler + * invocation. If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs + * + * then typically there will be rows for + * + * num | arg + * --- | --- + * 0 | --compiler + * 1 | *path to compiler* + * 2 | --cil + * 3 | f1.cs + * 4 | f2.cs + * 5 | f3.cs + */ +#keyset[id, num] +compilation_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 + * + * csc f1.cs f2.cs f3.cs + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | f1.cs + * 1 | f2.cs + * 2 | f3.cs + */ +#keyset[id, num] +compilation_compiling_files( + int id : @compilation ref, + int num : int ref, + int file : @file ref +); + +/** + * The references used by a compiler invocation. + * If `id` is for the compiler invocation + * + * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll + * + * then there will be rows for + * + * num | arg + * --- | --- + * 0 | ref1.dll + * 1 | ref2.dll + * 2 | ref3.dll + */ +#keyset[id, num] +compilation_referencing_files( + int id : @compilation ref, + int num : int ref, + int file : @file 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 +); + +diagnostics( + unique int id: @diagnostic, + 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 +); + +extractor_messages( + unique int id: @extractor_message, + int severity: int ref, + string origin : string ref, + string text : string ref, + string entity : string ref, + int location: @location_default ref, + string stack_trace : string 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`. + */ +compilation_finished( + unique int id : @compilation ref, + float cpu_seconds : float ref, + float elapsed_seconds : float ref +); + +compilation_assembly( + unique int id : @compilation ref, + int assembly: @assembly ref +) + +/* + * External artifacts + */ + +externalDefects( + unique int id: @externalDefect, + string queryPath: string ref, + int location: @location ref, + string message: string ref, + float severity: float ref); + +externalMetrics( + unique int id: @externalMetric, + string queryPath: string ref, + int location: @location ref, + float value: float ref); + +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); + +/* + * C# dbscheme + */ + +/** ELEMENTS **/ + +@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration + | @using_directive | @type_parameter_constraints | @external_element + | @xmllocatable | @asp_element | @namespace | @preprocessor_directive; + +@declaration = @callable | @generic | @assignable | @namespace; + +@named_element = @namespace | @declaration; + +@declaration_with_accessors = @property | @indexer | @event; + +@assignable = @variable | @assignable_with_accessors | @event; + +@assignable_with_accessors = @property | @indexer; + +@external_element = @externalMetric | @externalDefect | @externalDataElement; + +@attributable = @assembly | @field | @parameter | @operator | @method | @constructor + | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors + | @local_function; + +/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/ + +@location = @location_default | @assembly; + +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); + +locations_mapped( + unique int id: @location_default ref, + int mapped_to: @location_default ref); + +@sourceline = @file | @callable | @xmllocatable; + +numlines( + int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref); + +assemblies( + unique int id: @assembly, + int file: @file ref, + string fullname: string ref, + string name: string ref, + string version: string ref); + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files( + unique int id: @file, + string name: string ref, + string simple: string ref, + string ext: string ref, + int fromSource: int ref); + +folders( + unique int id: @folder, + string name: string ref, + string simple: string ref); + +@container = @folder | @file ; + +containerparent( + int parent: @container ref, + unique int child: @container ref); + +file_extraction_mode( + unique int file: @file ref, + int mode: int ref + /* 0 = normal, 1 = standalone extractor */ + ); + +/** NAMESPACES **/ + +@type_container = @namespace | @type; + +namespaces( + unique int id: @namespace, + string name: string ref); + +namespace_declarations( + unique int id: @namespace_declaration, + int namespace_id: @namespace ref); + +namespace_declaration_location( + unique int id: @namespace_declaration ref, + int loc: @location ref); + +parent_namespace( + unique int child_id: @type_container ref, + int namespace_id: @namespace ref); + +@declaration_or_directive = @namespace_declaration | @type | @using_directive; + +parent_namespace_declaration( + int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes + int namespace_id: @namespace_declaration ref); + +@using_directive = @using_namespace_directive | @using_static_directive; + +using_namespace_directives( + unique int id: @using_namespace_directive, + int namespace_id: @namespace ref); + +using_static_directives( + unique int id: @using_static_directive, + int type_id: @type_or_ref ref); + +using_directive_location( + unique int id: @using_directive ref, + int loc: @location ref); + +@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning + | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if + | @directive_elif | @directive_else | @directive_endif; + +@conditional_directive = @directive_if | @directive_elif; +@branch_directive = @directive_if | @directive_elif | @directive_else; + +directive_ifs( + unique int id: @directive_if, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref); /* 0: false, 1: true */ + +directive_elifs( + unique int id: @directive_elif, + int branchTaken: int ref, /* 0: false, 1: true */ + int conditionValue: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +directive_elses( + unique int id: @directive_else, + int branchTaken: int ref, /* 0: false, 1: true */ + int parent: @directive_if ref, + int index: int ref); + +#keyset[id, start] +directive_endifs( + unique int id: @directive_endif, + unique int start: @directive_if ref); + +directive_define_symbols( + unique int id: @define_symbol_expr ref, + string name: string ref); + +directive_regions( + unique int id: @directive_region, + string name: string ref); + +#keyset[id, start] +directive_endregions( + unique int id: @directive_endregion, + unique int start: @directive_region ref); + +directive_lines( + unique int id: @directive_line, + int kind: int ref); /* 0: default, 1: hidden, 2: numeric */ + +directive_line_value( + unique int id: @directive_line ref, + int line: int ref); + +directive_line_file( + unique int id: @directive_line ref, + int file: @file ref +) + +directive_nullables( + unique int id: @directive_nullable, + int setting: int ref, /* 0: disable, 1: enable, 2: restore */ + int target: int ref); /* 0: none, 1: annotations, 2: warnings */ + +directive_warnings( + unique int id: @directive_warning, + string message: string ref); + +directive_errors( + unique int id: @directive_error, + string message: string ref); + +directive_undefines( + unique int id: @directive_undefine, + string name: string ref); + +directive_defines( + unique int id: @directive_define, + string name: string ref); + +pragma_checksums( + unique int id: @pragma_checksum, + int file: @file ref, + string guid: string ref, + string bytes: string ref); + +pragma_warnings( + unique int id: @pragma_warning, + int kind: int ref /* 0 = disable, 1 = restore */); + +#keyset[id, index] +pragma_warning_error_codes( + int id: @pragma_warning ref, + string errorCode: string ref, + int index: int ref); + +preprocessor_directive_location( + unique int id: @preprocessor_directive ref, + int loc: @location ref); + +preprocessor_directive_compilation( + unique int id: @preprocessor_directive ref, + int compilation: @compilation ref); + +preprocessor_directive_active( + unique int id: @preprocessor_directive ref, + int active: int ref); /* 0: false, 1: true */ + +/** TYPES **/ + +types( + unique int id: @type, + int kind: int ref, + string name: string ref); + +case @type.kind of + 1 = @bool_type +| 2 = @char_type +| 3 = @decimal_type +| 4 = @sbyte_type +| 5 = @short_type +| 6 = @int_type +| 7 = @long_type +| 8 = @byte_type +| 9 = @ushort_type +| 10 = @uint_type +| 11 = @ulong_type +| 12 = @float_type +| 13 = @double_type +| 14 = @enum_type +| 15 = @struct_type +| 17 = @class_type +| 19 = @interface_type +| 20 = @delegate_type +| 21 = @null_type +| 22 = @type_parameter +| 23 = @pointer_type +| 24 = @nullable_type +| 25 = @array_type +| 26 = @void_type +| 27 = @int_ptr_type +| 28 = @uint_ptr_type +| 29 = @dynamic_type +| 30 = @arglist_type +| 31 = @unknown_type +| 32 = @tuple_type +| 33 = @function_pointer_type + ; + +@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type; +@integral_type = @signed_integral_type | @unsigned_integral_type; +@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type; +@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type; +@floating_point_type = @float_type | @double_type; +@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type + | @uint_ptr_type | @tuple_type; +@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type + | @dynamic_type; +@value_or_ref_type = @value_type | @ref_type; + +typerefs( + unique int id: @typeref, + string name: string ref); + +typeref_type( + int id: @typeref ref, + unique int typeId: @type ref); + +@type_or_ref = @type | @typeref; + +array_element_type( + unique int array: @array_type ref, + int dimension: int ref, + int rank: int ref, + int element: @type_or_ref ref); + +nullable_underlying_type( + unique int nullable: @nullable_type ref, + int underlying: @type_or_ref ref); + +pointer_referent_type( + unique int pointer: @pointer_type ref, + int referent: @type_or_ref ref); + +enum_underlying_type( + unique int enum_id: @enum_type ref, + int underlying_type_id: @type_or_ref ref); + +delegate_return_type( + unique int delegate_id: @delegate_type ref, + int return_type_id: @type_or_ref ref); + +function_pointer_return_type( + unique int function_pointer_id: @function_pointer_type ref, + int return_type_id: @type_or_ref ref); + +extend( + unique int sub: @type ref, + int super: @type_or_ref ref); + +anonymous_types( + unique int id: @type ref); + +@interface_or_ref = @interface_type | @typeref; + +implement( + int sub: @type ref, + int super: @type_or_ref ref); + +type_location( + int id: @type ref, + int loc: @location ref); + +tuple_underlying_type( + unique int tuple: @tuple_type ref, + int struct: @type_or_ref ref); + +#keyset[tuple, index] +tuple_element( + int tuple: @tuple_type ref, + int index: int ref, + unique int field: @field ref); + +attributes( + unique int id: @attribute, + int type_id: @type_or_ref ref, + int target: @attributable ref); + +attribute_location( + int id: @attribute ref, + int loc: @location ref); + +@type_mention_parent = @element | @type_mention; + +type_mention( + unique int id: @type_mention, + int type_id: @type_or_ref ref, + int parent: @type_mention_parent ref); + +type_mention_location( + unique int id: @type_mention ref, + int loc: @location ref); + +@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type; + +/** + * A direct annotation on an entity, for example `string? x;`. + * + * Annotations: + * 2 = reftype is not annotated "!" + * 3 = reftype is annotated "?" + * 4 = readonly ref type / in parameter + * 5 = ref type parameter, return or local variable + * 6 = out parameter + * + * Note that the annotation depends on the element it annotates. + * @assignable: The annotation is on the type of the assignable, for example the variable type. + * @type_parameter: The annotation is on the reftype constraint + * @callable: The annotation is on the return type + * @array_type: The annotation is on the element type + */ +type_annotation(int id: @has_type_annotation ref, int annotation: int ref); + +nullability(unique int nullability: @nullability, int kind: int ref); + +case @nullability.kind of + 0 = @oblivious +| 1 = @not_annotated +| 2 = @annotated +; + +#keyset[parent, index] +nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref) + +type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref); + +/** + * The nullable flow state of an expression, as determined by Roslyn. + * 0 = none (default, not populated) + * 1 = not null + * 2 = maybe null + */ +expr_flowstate(unique int id: @expr ref, int state: int ref); + +/** GENERICS **/ + +@generic = @type | @method | @local_function; + +type_parameters( + unique int id: @type_parameter ref, + int index: int ref, + int generic_id: @generic ref, + int variance: int ref /* none = 0, out = 1, in = 2 */); + +#keyset[constructed_id, index] +type_arguments( + int id: @type_or_ref ref, + int index: int ref, + int constructed_id: @generic_or_ref ref); + +@generic_or_ref = @generic | @typeref; + +constructed_generic( + unique int constructed: @generic ref, + int generic: @generic_or_ref ref); + +type_parameter_constraints( + unique int id: @type_parameter_constraints, + int param_id: @type_parameter ref); + +type_parameter_constraints_location( + int id: @type_parameter_constraints ref, + int loc: @location ref); + +general_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int kind: int ref /* class = 1, struct = 2, new = 3 */); + +specific_type_parameter_constraints( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref); + +specific_type_parameter_nullability( + int id: @type_parameter_constraints ref, + int base_id: @type_or_ref ref, + int nullability: @nullability ref); + +/** FUNCTION POINTERS */ + +function_pointer_calling_conventions( + int id: @function_pointer_type ref, + int kind: int ref); + +#keyset[id, index] +has_unmanaged_calling_conventions( + int id: @function_pointer_type ref, + int index: int ref, + int conv_id: @type_or_ref ref); + +/** MODIFIERS */ + +@modifiable = @modifiable_direct | @event_accessor; + +@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr; + +modifiers( + unique int id: @modifier, + string name: string ref); + +has_modifiers( + int id: @modifiable_direct ref, + int mod_id: @modifier ref); + +compiler_generated(unique int id: @modifiable_direct ref); + +/** MEMBERS **/ + +@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type; + +@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr; + +@virtualizable = @method | @property | @indexer | @event; + +exprorstmt_name( + unique int parent_id: @named_exprorstmt ref, + string name: string ref); + +nested_types( + unique int id: @type ref, + int declaring_type_id: @type ref, + int unbound_id: @type ref); + +properties( + unique int id: @property, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @property ref); + +property_location( + int id: @property ref, + int loc: @location ref); + +indexers( + unique int id: @indexer, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @indexer ref); + +indexer_location( + int id: @indexer ref, + int loc: @location ref); + +accessors( + unique int id: @accessor, + int kind: int ref, + string name: string ref, + int declaring_member_id: @member ref, + int unbound_id: @accessor ref); + +case @accessor.kind of + 1 = @getter +| 2 = @setter + ; + +init_only_accessors( + unique int id: @accessor ref); + +accessor_location( + int id: @accessor ref, + int loc: @location ref); + +events( + unique int id: @event, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @event ref); + +event_location( + int id: @event ref, + int loc: @location ref); + +event_accessors( + unique int id: @event_accessor, + int kind: int ref, + string name: string ref, + int declaring_event_id: @event ref, + int unbound_id: @event_accessor ref); + +case @event_accessor.kind of + 1 = @add_event_accessor +| 2 = @remove_event_accessor + ; + +event_accessor_location( + int id: @event_accessor ref, + int loc: @location ref); + +operators( + unique int id: @operator, + string name: string ref, + string symbol: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @operator ref); + +operator_location( + int id: @operator ref, + int loc: @location ref); + +constant_value( + int id: @variable ref, + string value: string ref); + +/** CALLABLES **/ + +@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function; + +@callable_accessor = @accessor | @event_accessor; + +methods( + unique int id: @method, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @method ref); + +method_location( + int id: @method ref, + int loc: @location ref); + +constructors( + unique int id: @constructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @constructor ref); + +constructor_location( + int id: @constructor ref, + int loc: @location ref); + +destructors( + unique int id: @destructor, + string name: string ref, + int declaring_type_id: @type ref, + int unbound_id: @destructor ref); + +destructor_location( + int id: @destructor ref, + int loc: @location ref); + +overrides( + int id: @callable ref, + int base_id: @callable ref); + +explicitly_implements( + int id: @member ref, + int interface_id: @interface_or_ref ref); + +local_functions( + unique int id: @local_function, + string name: string ref, + int return_type: @type ref, + int unbound_id: @local_function ref); + +local_function_stmts( + unique int fn: @local_function_stmt ref, + int stmt: @local_function ref); + +/** VARIABLES **/ + +@variable = @local_scope_variable | @field; + +@local_scope_variable = @local_variable | @parameter; + +fields( + unique int id: @field, + int kind: int ref, + string name: string ref, + int declaring_type_id: @type ref, + int type_id: @type_or_ref ref, + int unbound_id: @field ref); + +case @field.kind of + 1 = @addressable_field +| 2 = @constant + ; + +field_location( + int id: @field ref, + int loc: @location ref); + +localvars( + unique int id: @local_variable, + int kind: int ref, + string name: string ref, + int implicitly_typed: int ref /* 0 = no, 1 = yes */, + int type_id: @type_or_ref ref, + int parent_id: @local_var_decl_expr ref); + +case @local_variable.kind of + 1 = @addressable_local_variable +| 2 = @local_constant +| 3 = @local_variable_ref + ; + +localvar_location( + unique int id: @local_variable ref, + int loc: @location ref); + +@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type; + +#keyset[name, parent_id] +#keyset[index, parent_id] +params( + unique int id: @parameter, + string name: string ref, + int type_id: @type_or_ref ref, + int index: int ref, + int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */ + int parent_id: @parameterizable ref, + int unbound_id: @parameter ref); + +param_location( + int id: @parameter ref, + int loc: @location ref); + +/** STATEMENTS **/ + +@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent; + +statements( + unique int id: @stmt, + int kind: int ref); + +#keyset[index, parent] +stmt_parent( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_stmt_parent = @callable; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +stmt_parent_top_level( + unique int stmt: @stmt ref, + int index: int ref, + int parent: @top_level_stmt_parent ref); + +case @stmt.kind of + 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @switch_stmt +| 5 = @while_stmt +| 6 = @do_stmt +| 7 = @for_stmt +| 8 = @foreach_stmt +| 9 = @break_stmt +| 10 = @continue_stmt +| 11 = @goto_stmt +| 12 = @goto_case_stmt +| 13 = @goto_default_stmt +| 14 = @throw_stmt +| 15 = @return_stmt +| 16 = @yield_stmt +| 17 = @try_stmt +| 18 = @checked_stmt +| 19 = @unchecked_stmt +| 20 = @lock_stmt +| 21 = @using_block_stmt +| 22 = @var_decl_stmt +| 23 = @const_decl_stmt +| 24 = @empty_stmt +| 25 = @unsafe_stmt +| 26 = @fixed_stmt +| 27 = @label_stmt +| 28 = @catch +| 29 = @case_stmt +| 30 = @local_function_stmt +| 31 = @using_decl_stmt + ; + +@using_stmt = @using_block_stmt | @using_decl_stmt; + +@labeled_stmt = @label_stmt | @case; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt; + +@cond_stmt = @if_stmt | @switch_stmt; + +@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt; + +@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt + | @yield_stmt; + +@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; + + +stmt_location( + unique int id: @stmt ref, + int loc: @location ref); + +catch_type( + unique int catch_id: @catch ref, + int type_id: @type_or_ref ref, + int kind: int ref /* explicit = 1, implicit = 2 */); + +foreach_stmt_info( + unique int id: @foreach_stmt ref, + int kind: int ref /* non-async = 1, async = 2 */); + +@foreach_symbol = @method | @property | @type_or_ref; + +#keyset[id, kind] +foreach_stmt_desugar( + int id: @foreach_stmt ref, + int symbol: @foreach_symbol ref, + int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */); + +/** EXPRESSIONS **/ + +expressions( + unique int id: @expr, + int kind: int ref, + int type_id: @type_or_ref ref); + +#keyset[index, parent] +expr_parent( + unique int expr: @expr ref, + int index: int ref, + int parent: @control_flow_element ref); + +@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif; + +@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent; + +// [index, parent] is not a keyset because the same parent may be compiled multiple times +expr_parent_top_level( + unique int expr: @expr ref, + int index: int ref, + int parent: @top_level_exprorstmt_parent ref); + +case @expr.kind of +/* literal */ + 1 = @bool_literal_expr +| 2 = @char_literal_expr +| 3 = @decimal_literal_expr +| 4 = @int_literal_expr +| 5 = @long_literal_expr +| 6 = @uint_literal_expr +| 7 = @ulong_literal_expr +| 8 = @float_literal_expr +| 9 = @double_literal_expr +| 10 = @string_literal_expr +| 11 = @null_literal_expr +/* primary & unary */ +| 12 = @this_access_expr +| 13 = @base_access_expr +| 14 = @local_variable_access_expr +| 15 = @parameter_access_expr +| 16 = @field_access_expr +| 17 = @property_access_expr +| 18 = @method_access_expr +| 19 = @event_access_expr +| 20 = @indexer_access_expr +| 21 = @array_access_expr +| 22 = @type_access_expr +| 23 = @typeof_expr +| 24 = @method_invocation_expr +| 25 = @delegate_invocation_expr +| 26 = @operator_invocation_expr +| 27 = @cast_expr +| 28 = @object_creation_expr +| 29 = @explicit_delegate_creation_expr +| 30 = @implicit_delegate_creation_expr +| 31 = @array_creation_expr +| 32 = @default_expr +| 33 = @plus_expr +| 34 = @minus_expr +| 35 = @bit_not_expr +| 36 = @log_not_expr +| 37 = @post_incr_expr +| 38 = @post_decr_expr +| 39 = @pre_incr_expr +| 40 = @pre_decr_expr +/* multiplicative */ +| 41 = @mul_expr +| 42 = @div_expr +| 43 = @rem_expr +/* additive */ +| 44 = @add_expr +| 45 = @sub_expr +/* shift */ +| 46 = @lshift_expr +| 47 = @rshift_expr +/* relational */ +| 48 = @lt_expr +| 49 = @gt_expr +| 50 = @le_expr +| 51 = @ge_expr +/* equality */ +| 52 = @eq_expr +| 53 = @ne_expr +/* logical */ +| 54 = @bit_and_expr +| 55 = @bit_xor_expr +| 56 = @bit_or_expr +| 57 = @log_and_expr +| 58 = @log_or_expr +/* type testing */ +| 59 = @is_expr +| 60 = @as_expr +/* null coalescing */ +| 61 = @null_coalescing_expr +/* conditional */ +| 62 = @conditional_expr +/* assignment */ +| 63 = @simple_assign_expr +| 64 = @assign_add_expr +| 65 = @assign_sub_expr +| 66 = @assign_mul_expr +| 67 = @assign_div_expr +| 68 = @assign_rem_expr +| 69 = @assign_and_expr +| 70 = @assign_xor_expr +| 71 = @assign_or_expr +| 72 = @assign_lshift_expr +| 73 = @assign_rshift_expr +/* more */ +| 74 = @object_init_expr +| 75 = @collection_init_expr +| 76 = @array_init_expr +| 77 = @checked_expr +| 78 = @unchecked_expr +| 79 = @constructor_init_expr +| 80 = @add_event_expr +| 81 = @remove_event_expr +| 82 = @par_expr +| 83 = @local_var_decl_expr +| 84 = @lambda_expr +| 85 = @anonymous_method_expr +| 86 = @namespace_expr +/* dynamic */ +| 92 = @dynamic_element_access_expr +| 93 = @dynamic_member_access_expr +/* unsafe */ +| 100 = @pointer_indirection_expr +| 101 = @address_of_expr +| 102 = @sizeof_expr +/* async */ +| 103 = @await_expr +/* C# 6.0 */ +| 104 = @nameof_expr +| 105 = @interpolated_string_expr +| 106 = @unknown_expr +/* C# 7.0 */ +| 107 = @throw_expr +| 108 = @tuple_expr +| 109 = @local_function_invocation_expr +| 110 = @ref_expr +| 111 = @discard_expr +/* C# 8.0 */ +| 112 = @range_expr +| 113 = @index_expr +| 114 = @switch_expr +| 115 = @recursive_pattern_expr +| 116 = @property_pattern_expr +| 117 = @positional_pattern_expr +| 118 = @switch_case_expr +| 119 = @assign_coalesce_expr +| 120 = @suppress_nullable_warning_expr +| 121 = @namespace_access_expr +/* C# 9.0 */ +| 122 = @lt_pattern_expr +| 123 = @gt_pattern_expr +| 124 = @le_pattern_expr +| 125 = @ge_pattern_expr +| 126 = @not_pattern_expr +| 127 = @and_pattern_expr +| 128 = @or_pattern_expr +| 129 = @function_pointer_invocation_expr +/* Preprocessor */ +| 999 = @define_symbol_expr +; + +@switch = @switch_stmt | @switch_expr; +@case = @case_stmt | @switch_case_expr; +@pattern_match = @case | @is_expr; +@unary_pattern_expr = @not_pattern_expr; +@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr; +@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr; + +@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr; +@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr; +@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr + | @string_literal_expr | @null_literal_expr; + +@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr; +@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr; +@assign_event_expr = @add_event_expr | @remove_event_expr; + +@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr + | @assign_rem_expr +@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr + | @assign_lshift_expr | @assign_rshift_expr; + +@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr + | @method_access_expr | @type_access_expr | @dynamic_member_access_expr; +@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr; +@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr; + +@local_variable_access = @local_variable_access_expr | @local_var_decl_expr; +@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access; +@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr; + +@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr + | @event_access_expr | @dynamic_member_access_expr; + +@objectorcollection_init_expr = @object_init_expr | @collection_init_expr; + +@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr; + +@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr; +@incr_op_expr = @pre_incr_expr | @post_incr_expr; +@decr_op_expr = @pre_decr_expr | @post_decr_expr; +@mut_op_expr = @incr_op_expr | @decr_op_expr; +@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr; +@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr; + +@ternary_log_op_expr = @conditional_expr; +@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr; +@un_log_op_expr = @log_not_expr; +@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr; + +@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr + | @rshift_expr; +@un_bit_op_expr = @bit_not_expr; +@bit_expr = @un_bit_op_expr | @bin_bit_op_expr; + +@equality_op_expr = @eq_expr | @ne_expr; +@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr; +@comp_expr = @equality_op_expr | @rel_op_expr; + +@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op; + +@ternary_op = @ternary_log_op_expr; +@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr; +@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr + | @pointer_indirection_expr | @address_of_expr; + +@anonymous_function_expr = @lambda_expr | @anonymous_method_expr; + +@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr + | @delegate_invocation_expr | @object_creation_expr | @call_access_expr + | @local_function_invocation_expr | @function_pointer_invocation_expr; + +@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr; + +@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr + | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr; + +@throw_element = @throw_expr | @throw_stmt; + +@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr; + +implicitly_typed_array_creation( + unique int id: @array_creation_expr ref); + +explicitly_sized_array_creation( + unique int id: @array_creation_expr ref); + +stackalloc_array_creation( + unique int id: @array_creation_expr ref); + +implicitly_typed_object_creation( + unique int id: @implicitly_typeable_object_creation_expr ref); + +mutator_invocation_mode( + unique int id: @operator_invocation_expr ref, + int mode: int ref /* prefix = 1, postfix = 2*/); + +expr_compiler_generated( + unique int id: @expr ref); + +expr_value( + unique int id: @expr ref, + string value: string ref); + +expr_call( + unique int caller_id: @expr ref, + int target_id: @callable ref); + +expr_access( + unique int accesser_id: @access_expr ref, + int target_id: @accessible ref); + +@accessible = @method | @assignable | @local_function | @namespace; + +expr_location( + unique int id: @expr ref, + int loc: @location ref); + +dynamic_member_name( + unique int id: @late_bindable_expr ref, + string name: string ref); + +@qualifiable_expr = @member_access_expr + | @method_invocation_expr + | @element_access_expr; + +conditional_access( + unique int id: @qualifiable_expr ref); + +expr_argument( + unique int id: @expr ref, + int mode: int ref); + /* mode is the same as params: value = 0, ref = 1, out = 2 */ + +expr_argument_name( + unique int id: @expr ref, + string name: string ref); + +/** CONTROL/DATA FLOW **/ + +@control_flow_element = @stmt | @expr; + +/* 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; + +/* Comments */ + +commentline( + unique int id: @commentline, + int kind: int ref, + string text: string ref, + string rawtext: string ref); + +case @commentline.kind of + 0 = @singlelinecomment +| 1 = @xmldoccomment +| 2 = @multilinecomment; + +commentline_location( + unique int id: @commentline ref, + int loc: @location ref); + +commentblock( + unique int id : @commentblock); + +commentblock_location( + unique int id: @commentblock ref, + int loc: @location ref); + +commentblock_binding( + int id: @commentblock ref, + int entity: @element ref, + int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */ + +commentblock_child( + int id: @commentblock ref, + int commentline: @commentline ref, + int index: int ref); + +/* ASP.NET */ + +case @asp_element.kind of + 0=@asp_close_tag +| 1=@asp_code +| 2=@asp_comment +| 3=@asp_data_binding +| 4=@asp_directive +| 5=@asp_open_tag +| 6=@asp_quoted_string +| 7=@asp_text +| 8=@asp_xml_directive; + +@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string; + +asp_elements( + unique int id: @asp_element, + int kind: int ref, + int loc: @location ref); + +asp_comment_server(unique int comment: @asp_comment ref); +asp_code_inline(unique int code: @asp_code ref); +asp_directive_attribute( + int directive: @asp_directive ref, + int index: int ref, + string name: string ref, + int value: @asp_quoted_string ref); +asp_directive_name( + unique int directive: @asp_directive ref, + string name: string ref); +asp_element_body( + unique int element: @asp_element ref, + string body: string ref); +asp_tag_attribute( + int tag: @asp_open_tag ref, + int index: int ref, + string name: string ref, + int attribute: @asp_attribute ref); +asp_tag_name( + unique int tag: @asp_open_tag ref, + string name: string ref); +asp_tag_isempty(int tag: @asp_open_tag ref); + +/* Common Intermediate Language - CIL */ + +case @cil_instruction.opcode of + 0 = @cil_nop +| 1 = @cil_break +| 2 = @cil_ldarg_0 +| 3 = @cil_ldarg_1 +| 4 = @cil_ldarg_2 +| 5 = @cil_ldarg_3 +| 6 = @cil_ldloc_0 +| 7 = @cil_ldloc_1 +| 8 = @cil_ldloc_2 +| 9 = @cil_ldloc_3 +| 10 = @cil_stloc_0 +| 11 = @cil_stloc_1 +| 12 = @cil_stloc_2 +| 13 = @cil_stloc_3 +| 14 = @cil_ldarg_s +| 15 = @cil_ldarga_s +| 16 = @cil_starg_s +| 17 = @cil_ldloc_s +| 18 = @cil_ldloca_s +| 19 = @cil_stloc_s +| 20 = @cil_ldnull +| 21 = @cil_ldc_i4_m1 +| 22 = @cil_ldc_i4_0 +| 23 = @cil_ldc_i4_1 +| 24 = @cil_ldc_i4_2 +| 25 = @cil_ldc_i4_3 +| 26 = @cil_ldc_i4_4 +| 27 = @cil_ldc_i4_5 +| 28 = @cil_ldc_i4_6 +| 29 = @cil_ldc_i4_7 +| 30 = @cil_ldc_i4_8 +| 31 = @cil_ldc_i4_s +| 32 = @cil_ldc_i4 +| 33 = @cil_ldc_i8 +| 34 = @cil_ldc_r4 +| 35 = @cil_ldc_r8 +| 37 = @cil_dup +| 38 = @cil_pop +| 39 = @cil_jmp +| 40 = @cil_call +| 41 = @cil_calli +| 42 = @cil_ret +| 43 = @cil_br_s +| 44 = @cil_brfalse_s +| 45 = @cil_brtrue_s +| 46 = @cil_beq_s +| 47 = @cil_bge_s +| 48 = @cil_bgt_s +| 49 = @cil_ble_s +| 50 = @cil_blt_s +| 51 = @cil_bne_un_s +| 52 = @cil_bge_un_s +| 53 = @cil_bgt_un_s +| 54 = @cil_ble_un_s +| 55 = @cil_blt_un_s +| 56 = @cil_br +| 57 = @cil_brfalse +| 58 = @cil_brtrue +| 59 = @cil_beq +| 60 = @cil_bge +| 61 = @cil_bgt +| 62 = @cil_ble +| 63 = @cil_blt +| 64 = @cil_bne_un +| 65 = @cil_bge_un +| 66 = @cil_bgt_un +| 67 = @cil_ble_un +| 68 = @cil_blt_un +| 69 = @cil_switch +| 70 = @cil_ldind_i1 +| 71 = @cil_ldind_u1 +| 72 = @cil_ldind_i2 +| 73 = @cil_ldind_u2 +| 74 = @cil_ldind_i4 +| 75 = @cil_ldind_u4 +| 76 = @cil_ldind_i8 +| 77 = @cil_ldind_i +| 78 = @cil_ldind_r4 +| 79 = @cil_ldind_r8 +| 80 = @cil_ldind_ref +| 81 = @cil_stind_ref +| 82 = @cil_stind_i1 +| 83 = @cil_stind_i2 +| 84 = @cil_stind_i4 +| 85 = @cil_stind_i8 +| 86 = @cil_stind_r4 +| 87 = @cil_stind_r8 +| 88 = @cil_add +| 89 = @cil_sub +| 90 = @cil_mul +| 91 = @cil_div +| 92 = @cil_div_un +| 93 = @cil_rem +| 94 = @cil_rem_un +| 95 = @cil_and +| 96 = @cil_or +| 97 = @cil_xor +| 98 = @cil_shl +| 99 = @cil_shr +| 100 = @cil_shr_un +| 101 = @cil_neg +| 102 = @cil_not +| 103 = @cil_conv_i1 +| 104 = @cil_conv_i2 +| 105 = @cil_conv_i4 +| 106 = @cil_conv_i8 +| 107 = @cil_conv_r4 +| 108 = @cil_conv_r8 +| 109 = @cil_conv_u4 +| 110 = @cil_conv_u8 +| 111 = @cil_callvirt +| 112 = @cil_cpobj +| 113 = @cil_ldobj +| 114 = @cil_ldstr +| 115 = @cil_newobj +| 116 = @cil_castclass +| 117 = @cil_isinst +| 118 = @cil_conv_r_un +| 121 = @cil_unbox +| 122 = @cil_throw +| 123 = @cil_ldfld +| 124 = @cil_ldflda +| 125 = @cil_stfld +| 126 = @cil_ldsfld +| 127 = @cil_ldsflda +| 128 = @cil_stsfld +| 129 = @cil_stobj +| 130 = @cil_conv_ovf_i1_un +| 131 = @cil_conv_ovf_i2_un +| 132 = @cil_conv_ovf_i4_un +| 133 = @cil_conv_ovf_i8_un +| 134 = @cil_conv_ovf_u1_un +| 135 = @cil_conv_ovf_u2_un +| 136 = @cil_conv_ovf_u4_un +| 137 = @cil_conv_ovf_u8_un +| 138 = @cil_conv_ovf_i_un +| 139 = @cil_conv_ovf_u_un +| 140 = @cil_box +| 141 = @cil_newarr +| 142 = @cil_ldlen +| 143 = @cil_ldelema +| 144 = @cil_ldelem_i1 +| 145 = @cil_ldelem_u1 +| 146 = @cil_ldelem_i2 +| 147 = @cil_ldelem_u2 +| 148 = @cil_ldelem_i4 +| 149 = @cil_ldelem_u4 +| 150 = @cil_ldelem_i8 +| 151 = @cil_ldelem_i +| 152 = @cil_ldelem_r4 +| 153 = @cil_ldelem_r8 +| 154 = @cil_ldelem_ref +| 155 = @cil_stelem_i +| 156 = @cil_stelem_i1 +| 157 = @cil_stelem_i2 +| 158 = @cil_stelem_i4 +| 159 = @cil_stelem_i8 +| 160 = @cil_stelem_r4 +| 161 = @cil_stelem_r8 +| 162 = @cil_stelem_ref +| 163 = @cil_ldelem +| 164 = @cil_stelem +| 165 = @cil_unbox_any +| 179 = @cil_conv_ovf_i1 +| 180 = @cil_conv_ovf_u1 +| 181 = @cil_conv_ovf_i2 +| 182 = @cil_conv_ovf_u2 +| 183 = @cil_conv_ovf_i4 +| 184 = @cil_conv_ovf_u4 +| 185 = @cil_conv_ovf_i8 +| 186 = @cil_conv_ovf_u8 +| 194 = @cil_refanyval +| 195 = @cil_ckinfinite +| 198 = @cil_mkrefany +| 208 = @cil_ldtoken +| 209 = @cil_conv_u2 +| 210 = @cil_conv_u1 +| 211 = @cil_conv_i +| 212 = @cil_conv_ovf_i +| 213 = @cil_conv_ovf_u +| 214 = @cil_add_ovf +| 215 = @cil_add_ovf_un +| 216 = @cil_mul_ovf +| 217 = @cil_mul_ovf_un +| 218 = @cil_sub_ovf +| 219 = @cil_sub_ovf_un +| 220 = @cil_endfinally +| 221 = @cil_leave +| 222 = @cil_leave_s +| 223 = @cil_stind_i +| 224 = @cil_conv_u +| 65024 = @cil_arglist +| 65025 = @cil_ceq +| 65026 = @cil_cgt +| 65027 = @cil_cgt_un +| 65028 = @cil_clt +| 65029 = @cil_clt_un +| 65030 = @cil_ldftn +| 65031 = @cil_ldvirtftn +| 65033 = @cil_ldarg +| 65034 = @cil_ldarga +| 65035 = @cil_starg +| 65036 = @cil_ldloc +| 65037 = @cil_ldloca +| 65038 = @cil_stloc +| 65039 = @cil_localloc +| 65041 = @cil_endfilter +| 65042 = @cil_unaligned +| 65043 = @cil_volatile +| 65044 = @cil_tail +| 65045 = @cil_initobj +| 65046 = @cil_constrained +| 65047 = @cil_cpblk +| 65048 = @cil_initblk +| 65050 = @cil_rethrow +| 65052 = @cil_sizeof +| 65053 = @cil_refanytype +| 65054 = @cil_readonly +; + +// CIL ignored instructions + +@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned; + +// CIL local/parameter/field access + +@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga; +@cil_starg_any = @cil_starg | @cil_starg_s; + +@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca; +@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc; + +@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda; +@cil_stfld_any = @cil_stfld | @cil_stsfld; + +@cil_local_access = @cil_stloc_any | @cil_ldloc_any; +@cil_arg_access = @cil_starg_any | @cil_ldarg_any; +@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any; +@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any; + +@cil_stack_access = @cil_local_access | @cil_arg_access; +@cil_field_access = @cil_ldfld_any | @cil_stfld_any; + +@cil_access = @cil_read_access | @cil_write_access; + +// CIL constant/literal instructions + +@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8; + +@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 | + @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4; + +@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8; + +@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr; + +// Control flow + +@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump; +@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s | + @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s | + @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt | + @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un; +@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch; +@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any; +@cil_leave_any = @cil_leave | @cil_leave_s; +@cil_jump = @cil_unconditional_jump | @cil_conditional_jump; + +// CIL call instructions + +@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj; + +// CIL expression instructions + +@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access | + @cil_newarr | @cil_ldtoken | @cil_sizeof | + @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup; + +@cil_unary_expr = + @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation| + @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any | + @cil_ldind | @cil_unbox; + +@cil_conversion_operation = + @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 | + @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 | + @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un | + @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un | + @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un | + @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un | + @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un | + @cil_conv_i | @cil_conv_u | @cil_conv_r_un; + +@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 | + @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4; + +@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 | + @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref; + +@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation; + +@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl; + +@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un | + @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un | + @cil_sub_ovf | @cil_sub_ovf_un; + +@cil_unary_bitwise_operation = @cil_not; + +@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation; + +@cil_unary_arithmetic_operation = @cil_neg; + +@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un; + +// Elements that retrieve an address of something +@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema; + +// CIL array instructions + +@cil_read_array = + @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i | + @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 | + @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4; + +@cil_write_array = @cil_stelem | @cil_stelem_ref | + @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 | + @cil_stelem_r4 | @cil_stelem_r8; + +@cil_throw_any = @cil_throw | @cil_rethrow; + +#keyset[impl, index] +cil_instruction( + unique int id: @cil_instruction, + int opcode: int ref, + int index: int ref, + int impl: @cil_method_implementation ref); + +cil_jump( + unique int instruction: @cil_jump ref, + int target: @cil_instruction ref); + +cil_access( + unique int instruction: @cil_instruction ref, + int target: @cil_accessible ref); + +cil_value( + unique int instruction: @cil_literal ref, + string value: string ref); + +#keyset[instruction, index] +cil_switch( + int instruction: @cil_switch ref, + int index: int ref, + int target: @cil_instruction ref); + +cil_instruction_location( + unique int id: @cil_instruction ref, + int loc: @location ref); + +cil_type_location( + int id: @cil_type ref, + int loc: @location ref); + +cil_method_location( + int id: @cil_method ref, + int loc: @location ref); + +@cil_namespace = @namespace; + +@cil_type_container = @cil_type | @cil_namespace | @cil_method; + +case @cil_type.kind of + 0 = @cil_valueorreftype +| 1 = @cil_typeparameter +| 2 = @cil_array_type +| 3 = @cil_pointer_type +| 4 = @cil_function_pointer_type +; + +cil_type( + unique int id: @cil_type, + string name: string ref, + int kind: int ref, + int parent: @cil_type_container ref, + int sourceDecl: @cil_type ref); + +cil_pointer_type( + unique int id: @cil_pointer_type ref, + int pointee: @cil_type ref); + +cil_array_type( + unique int id: @cil_array_type ref, + int element_type: @cil_type ref, + int rank: int ref); + +cil_function_pointer_return_type( + unique int id: @cil_function_pointer_type ref, + int return_type: @cil_type ref); + +cil_method( + unique int id: @cil_method, + string name: string ref, + int parent: @cil_type ref, + int return_type: @cil_type ref); + +cil_method_source_declaration( + unique int method: @cil_method ref, + int source: @cil_method ref); + +cil_method_implementation( + unique int id: @cil_method_implementation, + int method: @cil_method ref, + int location: @assembly ref); + +cil_implements( + int id: @cil_method ref, + int decl: @cil_method ref); + +#keyset[parent, name] +cil_field( + unique int id: @cil_field, + int parent: @cil_type ref, + string name: string ref, + int field_type: @cil_type ref); + +@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace; +@cil_named_element = @cil_declaration | @cil_namespace; +@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member; +@cil_accessible = @cil_declaration; +@cil_variable = @cil_field | @cil_stack_variable; +@cil_stack_variable = @cil_local_variable | @cil_parameter; +@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event; +@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type; +@cil_parameterizable = @cil_method | @cil_function_pointer_type; +@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type; + +#keyset[parameterizable, index] +cil_parameter( + unique int id: @cil_parameter, + int parameterizable: @cil_parameterizable ref, + int index: int ref, + int param_type: @cil_type ref); + +cil_parameter_in(unique int id: @cil_parameter ref); +cil_parameter_out(unique int id: @cil_parameter ref); + +cil_setter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +#keyset[id, modifier] +cil_custom_modifiers( + int id: @cil_custom_modifier_receiver ref, + int modifier: @cil_type ref, + int kind: int ref); // modreq: 1, modopt: 0 + +cil_type_annotation( + int id: @cil_has_type_annotation ref, + int annotation: int ref); + +cil_getter(unique int prop: @cil_property ref, + int method: @cil_method ref); + +cil_adder(unique int event: @cil_event ref, + int method: @cil_method ref); + +cil_remover(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref); + +cil_property( + unique int id: @cil_property, + int parent: @cil_type ref, + string name: string ref, + int property_type: @cil_type ref); + +#keyset[parent, name] +cil_event(unique int id: @cil_event, + int parent: @cil_type ref, + string name: string ref, + int event_type: @cil_type ref); + +#keyset[impl, index] +cil_local_variable( + unique int id: @cil_local_variable, + int impl: @cil_method_implementation ref, + int index: int ref, + int var_type: @cil_type ref); + +cil_function_pointer_calling_conventions( + int id: @cil_function_pointer_type ref, + int kind: int ref); + +// CIL handlers (exception handlers etc). + +case @cil_handler.kind of + 0 = @cil_catch_handler +| 1 = @cil_filter_handler +| 2 = @cil_finally_handler +| 4 = @cil_fault_handler +; + +#keyset[impl, index] +cil_handler( + unique int id: @cil_handler, + int impl: @cil_method_implementation ref, + int index: int ref, + int kind: int ref, + int try_start: @cil_instruction ref, + int try_end: @cil_instruction ref, + int handler_start: @cil_instruction ref); + +cil_handler_filter( + unique int id: @cil_handler ref, + int filter_start: @cil_instruction ref); + +cil_handler_type( + unique int id: @cil_handler ref, + int catch_type: @cil_type ref); + +@cil_controlflow_node = @cil_entry_point | @cil_instruction; + +@cil_entry_point = @cil_method_implementation | @cil_handler; + +@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method; + +cil_method_stack_size( + unique int method: @cil_method_implementation ref, + int size: int ref); + +// CIL modifiers + +cil_public(int id: @cil_member ref); +cil_private(int id: @cil_member ref); +cil_protected(int id: @cil_member ref); +cil_internal(int id: @cil_member ref); +cil_static(int id: @cil_member ref); +cil_sealed(int id: @cil_member ref); +cil_virtual(int id: @cil_method ref); +cil_abstract(int id: @cil_member ref); +cil_class(int id: @cil_type ref); +cil_interface(int id: @cil_type ref); +cil_security(int id: @cil_member ref); +cil_requiresecobject(int id: @cil_method ref); +cil_specialname(int id: @cil_method ref); +cil_newslot(int id: @cil_method ref); + +cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref); +cil_base_interface(int id: @cil_type ref, int base: @cil_type ref); +cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref); + +#keyset[unbound, index] +cil_type_parameter( + int unbound: @cil_member ref, + int index: int ref, + int param: @cil_typeparameter ref); + +#keyset[bound, index] +cil_type_argument( + int bound: @cil_member ref, + int index: int ref, + int t: @cil_type ref); + +// CIL type parameter constraints + +cil_typeparam_covariant(int tp: @cil_typeparameter ref); +cil_typeparam_contravariant(int tp: @cil_typeparameter ref); +cil_typeparam_class(int tp: @cil_typeparameter ref); +cil_typeparam_struct(int tp: @cil_typeparameter ref); +cil_typeparam_new(int tp: @cil_typeparameter ref); +cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref); + +// CIL attributes + +cil_attribute( + unique int attributeid: @cil_attribute, + int element: @cil_declaration ref, + int constructor: @cil_method ref); + +#keyset[attribute_id, param] +cil_attribute_named_argument( + int attribute_id: @cil_attribute ref, + string param: string ref, + string value: string ref); + +#keyset[attribute_id, index] +cil_attribute_positional_argument( + int attribute_id: @cil_attribute ref, + int index: int ref, + string value: string ref); + + +// Common .Net data model covering both C# and CIL + +// Common elements +@dotnet_element = @element | @cil_element; +@dotnet_named_element = @named_element | @cil_named_element; +@dotnet_callable = @callable | @cil_method; +@dotnet_variable = @variable | @cil_variable; +@dotnet_field = @field | @cil_field; +@dotnet_parameter = @parameter | @cil_parameter; +@dotnet_declaration = @declaration | @cil_declaration; +@dotnet_member = @member | @cil_member; +@dotnet_event = @event | @cil_event; +@dotnet_property = @property | @cil_property | @indexer; +@dotnet_parameterizable = @parameterizable | @cil_parameterizable; + +// Common types +@dotnet_type = @type | @cil_type; +@dotnet_call = @call | @cil_call_any; +@dotnet_throw = @throw_element | @cil_throw_any; +@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type; +@dotnet_typeparameter = @type_parameter | @cil_typeparameter; +@dotnet_array_type = @array_type | @cil_array_type; +@dotnet_pointer_type = @pointer_type | @cil_pointer_type; +@dotnet_type_parameter = @type_parameter | @cil_typeparameter; +@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable; + +// Attributes +@dotnet_attribute = @attribute | @cil_attribute; + +// Expressions +@dotnet_expr = @expr | @cil_expr; + +// Literals +@dotnet_literal = @literal_expr | @cil_literal; +@dotnet_string_literal = @string_literal_expr | @cil_ldstr; +@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i; +@dotnet_float_literal = @float_literal_expr | @cil_ldc_r; +@dotnet_null_literal = @null_literal_expr | @cil_ldnull; + +@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property | + @callable | @value_or_ref_type | @void_type; + +#keyset[entity, location] +metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref) diff --git a/csharp/upgrades/TO_CHANGE/upgrade.properties b/csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/upgrade.properties similarity index 100% rename from csharp/upgrades/TO_CHANGE/upgrade.properties rename to csharp/upgrades/68db341c2ed1693c2ae6e20ad533c84138cb275a/upgrade.properties From 6d908876e0ff3ea8648228326a06943d90f55f22 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 5 Feb 2021 09:31:16 +0100 Subject: [PATCH 226/429] Add new .stats file --- .../ql/src/semmlecode.csharp.dbscheme.stats | 15991 ++++++++-------- 1 file changed, 8235 insertions(+), 7756 deletions(-) diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme.stats b/csharp/ql/src/semmlecode.csharp.dbscheme.stats index c294897e009..bb3e0fcb650 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme.stats +++ b/csharp/ql/src/semmlecode.csharp.dbscheme.stats @@ -1,7 +1,7 @@ @compilation -564 +1095 @diagnostic @@ -9,7 +9,7 @@ @extractor_message -750 +7638 @externalDefect @@ -21,11 +21,11 @@ @externalDataElement -15 +29 @duplication -11701 +22735 @similarity @@ -33,67 +33,67 @@ @location_default -11326677 +14080010 @assembly -2160 +4198 @file -24351 +47312 @folder -9177 +17831 @namespace -11293 +21942 @namespace_declaration -8355 +19760 @using_namespace_directive -66100 +144252 @using_static_directive -199 +390 @directive_if -2550 +5161 @directive_elif -7 +59 @directive_else -1140 +2314 @directive_endif -2550 +5161 @directive_region -565 +1954 @directive_endregion -565 +1954 @directive_line -128896 +250436 @directive_nullable -83477 +162190 @directive_warning @@ -101,7 +101,7 @@ @directive_error -1 +28 @directive_undefine @@ -109,119 +109,119 @@ @directive_define -5 +22 @pragma_checksum -2494 +4846 @pragma_warning -14725 +28609 @bool_type -2 +4 @char_type -2 +4 @decimal_type -2 +4 @sbyte_type -2 +4 @short_type -2 +4 @int_type -2 +4 @long_type -2 +4 @byte_type -2 +4 @ushort_type -2 +4 @uint_type -2 +4 @ulong_type -2 +4 @float_type -2 +4 @double_type -2 +4 @enum_type -6141 +11952 @struct_type -24822 +49665 @class_type -154426 +305098 @interface_type -88664 +178112 @delegate_type -52237 +107567 @null_type -2 +4 @type_parameter -102321 +202597 @pointer_type -112 +219 @nullable_type -550 +979 @array_type -4384 +9122 @void_type -2 +4 @int_ptr_type -2 +4 @tuple_type -857 +1782 @uint_ptr_type @@ -229,7 +229,7 @@ @dynamic_type -2 +4 @arglist_type @@ -241,495 +241,495 @@ @function_pointer_type -9 +11 @typeref -120781 +234791 @attribute -368399 +745454 @type_mention -622003 +1252212 @oblivious -664 +1315 @not_annotated -300 +618 @annotated -75 +113 @type_parameter_constraints -273733 +594129 @modifier -42 +82 @property -212542 +425592 @indexer -7590 +17042 @getter -220012 +442401 @setter -64470 +127526 @event -7838 +15230 @add_event_accessor -7838 +15230 @remove_event_accessor -7838 +15230 @operator -6201 +12410 @method -549172 +1117636 @constructor -138720 +277979 @destructor -225 +443 @local_function -488 +1801 @addressable_field -188270 +371421 @constant -95194 +185214 @addressable_local_variable -72587 +162452 @local_constant -373 +799 @local_variable_ref -67 - - -@parameter -1189134 - - -@block_stmt -159797 - - -@expr_stmt -178398 - - -@return_stmt -40051 - - -@using_block_stmt -517 - - -@var_decl_stmt -67553 - - -@if_stmt -50740 - - -@switch_stmt -1447 - - -@while_stmt -1984 - - -@do_stmt -386 - - -@for_stmt -3124 - - -@foreach_stmt -1910 - - -@break_stmt -5413 - - -@continue_stmt -1168 - - -@goto_stmt -1045 - - -@goto_case_stmt -154 - - -@goto_default_stmt -61 - - -@throw_stmt -50988 - - -@yield_stmt -194 - - -@try_stmt -2011 - - -@checked_stmt -146 - - -@unchecked_stmt -36 - - -@lock_stmt -496 - - -@const_decl_stmt -373 - - -@empty_stmt -115 - - -@unsafe_stmt -53 - - -@fixed_stmt -496 - - -@label_stmt -423 - - -@catch -1719 - - -@case_stmt -10966 - - -@local_function_stmt -488 - - -@using_decl_stmt -189 - - -@bool_literal_expr -40242 - - -@int_literal_expr -408062 - - -@long_literal_expr -153 - - -@double_literal_expr -337 - - -@string_literal_expr -207177 - - -@null_literal_expr -64946 - - -@local_variable_access_expr -233847 - - -@parameter_access_expr -146824 - - -@field_access_expr -226547 - - -@property_access_expr -168128 - - -@type_access_expr -170095 - - -@typeof_expr -23893 - - -@method_invocation_expr -259436 - - -@cast_expr -107752 - - -@object_creation_expr -28063 - - -@array_creation_expr -90105 - - -@array_init_expr -89964 - - -@local_var_decl_expr -72969 - - -@char_literal_expr -8057 - - -@decimal_literal_expr -49 - - -@uint_literal_expr -811 - - -@ulong_literal_expr -189 - - -@float_literal_expr -123 - - -@this_access_expr -293267 - - -@base_access_expr -1617 - - -@method_access_expr -3188 - - -@event_access_expr -162 - - -@indexer_access_expr -14740 - - -@array_access_expr -10091 - - -@delegate_invocation_expr -783 - - -@operator_invocation_expr -12666 - - -@explicit_delegate_creation_expr -482 - - -@implicit_delegate_creation_expr -2546 - - -@default_expr -3354 - - -@plus_expr -12 - - -@minus_expr -2658 - - -@bit_not_expr 264 +@parameter +2417427 + + +@block_stmt +306459 + + +@expr_stmt +367208 + + +@return_stmt +94364 + + +@using_block_stmt +1140 + + +@var_decl_stmt +147598 + + +@if_stmt +117703 + + +@switch_stmt +3065 + + +@while_stmt +4447 + + +@do_stmt +981 + + +@for_stmt +6794 + + +@foreach_stmt +5352 + + +@break_stmt +11004 + + +@continue_stmt +2218 + + +@goto_stmt +2733 + + +@goto_case_stmt +329 + + +@goto_default_stmt +145 + + +@throw_stmt +75132 + + +@yield_stmt +680 + + +@try_stmt +4294 + + +@checked_stmt +253 + + +@unchecked_stmt +104 + + +@lock_stmt +1523 + + +@const_decl_stmt +799 + + +@empty_stmt +351 + + +@unsafe_stmt +182 + + +@fixed_stmt +1149 + + +@label_stmt +1017 + + +@catch +3419 + + +@case_stmt +22718 + + +@local_function_stmt +1792 + + +@using_decl_stmt +551 + + +@bool_literal_expr +69328 + + +@int_literal_expr +752491 + + +@long_literal_expr +331 + + +@double_literal_expr +864 + + +@string_literal_expr +411643 + + +@null_literal_expr +107815 + + +@local_variable_access_expr +522589 + + +@parameter_access_expr +353685 + + +@field_access_expr +459628 + + +@property_access_expr +359104 + + +@type_access_expr +346616 + + +@typeof_expr +33657 + + +@method_invocation_expr +547072 + + +@cast_expr +264239 + + +@object_creation_expr +62511 + + +@array_creation_expr +179799 + + +@array_init_expr +179348 + + +@local_var_decl_expr +163320 + + +@char_literal_expr +16183 + + +@decimal_literal_expr +93 + + +@uint_literal_expr +2406 + + +@ulong_literal_expr +390 + + +@float_literal_expr +454 + + +@this_access_expr +591816 + + +@base_access_expr +2840 + + +@method_access_expr +9222 + + +@event_access_expr +433 + + +@indexer_access_expr +30757 + + +@array_access_expr +19356 + + +@delegate_invocation_expr +2001 + + +@operator_invocation_expr +29946 + + +@explicit_delegate_creation_expr +679 + + +@implicit_delegate_creation_expr +5109 + + +@default_expr +6144 + + +@plus_expr +45 + + +@minus_expr +7069 + + +@bit_not_expr +738 + + @log_not_expr -12491 +26384 @post_incr_expr -5382 +12312 @post_decr_expr -698 +1697 @pre_incr_expr -671 +1261 @pre_decr_expr -125 +406 @mul_expr -1387 +4626 @div_expr -612 +1791 @rem_expr -276 +704 @add_expr -12723 +27751 @sub_expr -4948 +12573 @lshift_expr -914 +4121 @rshift_expr -707 +1763 @lt_expr -6804 +15922 @gt_expr -3980 +9379 @le_expr -1422 +3829 @ge_expr -2380 +6014 @eq_expr -23261 +53515 @ne_expr -16042 +37219 @bit_and_expr -2303 +6298 @bit_xor_expr -217 +528 @bit_or_expr -6954 +15227 @log_and_expr -9148 +21263 @log_or_expr -6420 +14197 @is_expr -3108 +6486 @as_expr -1363 +2728 @null_coalescing_expr -1422 +3615 @conditional_expr -3413 +8972 @simple_assign_expr -79093 +167202 @assign_add_expr @@ -737,67 +737,67 @@ @assign_sub_expr -434 +1021 @assign_mul_expr -81 +182 @assign_div_expr -44 +99 @assign_rem_expr -3 +14 @assign_and_expr -103 +340 @assign_xor_expr -49 +114 @assign_or_expr -562 +1412 @assign_lshift_expr -31 +118 @assign_rshift_expr -64 +216 @object_init_expr -3456 +7685 @collection_init_expr -265 +594 @checked_expr -140 +326 @unchecked_expr -609 +1421 @constructor_init_expr -3163 +5796 @add_event_expr -63 +172 @remove_event_expr -53 +121 @par_expr @@ -805,11 +805,11 @@ @lambda_expr -23125 +48769 @anonymous_method_expr -41 +86 @namespace_expr @@ -817,35 +817,35 @@ @dynamic_element_access_expr -117 +331 @dynamic_member_access_expr -2975 +6843 @pointer_indirection_expr -1878 +4141 @address_of_expr -475 +1289 @sizeof_expr -255 +1061 @await_expr -25782 +54750 @nameof_expr -5774 +15584 @interpolated_string_expr -894 +3042 @unknown_expr @@ -853,71 +853,71 @@ @throw_expr -643 +1527 @tuple_expr -440 +1450 @local_function_invocation_expr -1187 +7490 @ref_expr -124 +459 @discard_expr -317 +903 @range_expr -15 +33 @index_expr -21 +47 @switch_expr -199 +508 @recursive_pattern_expr -199 +1011 @property_pattern_expr -154 +836 @positional_pattern_expr -45 +172 @switch_case_expr -2068 +4334 @assign_coalesce_expr -183 +544 @suppress_nullable_warning_expr -5940 +13849 @namespace_access_expr -11 +20 @lt_pattern_expr -1 +2 @gt_pattern_expr -2 +5 @le_pattern_expr @@ -929,27 +929,27 @@ @not_pattern_expr -19 +70 @and_pattern_expr -2 +3 @or_pattern_expr -21 +34 @function_pointer_invocation_expr -4 +6 @define_symbol_expr -3314 +6226 @xmldtd -5 +6 @xmlelement @@ -973,19 +973,19 @@ @singlelinecomment -86064 +189072 @multilinecomment -7533 +22567 @xmldoccomment -638 +207952 @commentblock -42325 +147802 @asp_close_tag @@ -1025,7 +1025,7 @@ @cil_nop -712327 +837337 @cil_break @@ -1033,147 +1033,147 @@ @cil_ldarg_0 -2043128 +3969647 @cil_ldarg_1 -625320 +1214950 @cil_ldarg_2 -228137 +443253 @cil_ldarg_3 -107503 +208870 @cil_ldloc_0 -477604 +927950 @cil_ldloc_1 -253859 +493230 @cil_ldloc_2 -148392 +288314 @cil_ldloc_3 -98711 +191789 @cil_stloc_0 -269813 +524227 @cil_stloc_1 -133892 +260143 @cil_stloc_2 -101925 +198033 @cil_stloc_3 -71081 +138105 @cil_ldarg_s -135953 +264147 @cil_ldarga_s -38429 +74666 @cil_starg_s -19107 +37123 @cil_ldloc_s -352774 +685414 @cil_ldloca_s -323414 +628370 @cil_stloc_s -247141 +480177 @cil_ldnull -310296 +602882 @cil_ldc_i4_m1 -64864 +126026 @cil_ldc_i4_0 -321534 +624717 @cil_ldc_i4_1 -254240 +493970 @cil_ldc_i4_2 -62207 +120863 @cil_ldc_i4_3 -32972 +64062 @cil_ldc_i4_4 -30262 +58797 @cil_ldc_i4_5 -19881 +38628 @cil_ldc_i4_6 -11957 +23232 @cil_ldc_i4_7 -10666 +20724 @cil_ldc_i4_8 -17209 +33436 @cil_ldc_i4_s -217583 +422748 @cil_ldc_i4 -262565 +510146 @cil_ldc_i8 -2511 +4880 @cil_ldc_r4 -5274 +10247 @cil_ldc_r8 -5309 +10315 @cil_dup -432865 +841025 @cil_pop -131816 +256110 @cil_jmp @@ -1181,7 +1181,7 @@ @cil_call -1409225 +2738019 @cil_calli @@ -1189,283 +1189,283 @@ @cil_ret -918306 +1784201 @cil_br_s -191079 +345383 @cil_brfalse_s -239525 +465380 @cil_brtrue_s -221401 +430166 @cil_beq_s -42285 +82157 @cil_bge_s -17953 +34883 @cil_bgt_s -8480 +16477 @cil_ble_s -15010 +29165 @cil_blt_s -31322 +60858 @cil_bne_un_s -52771 +102530 @cil_bge_un_s -1123 +2182 @cil_bgt_un_s -4489 +8723 @cil_ble_un_s -3146 +6112 @cil_blt_un_s -754 +1466 @cil_br -49429 +96038 @cil_brfalse -16652 +32355 @cil_brtrue -14050 +27299 @cil_beq -11057 +21484 @cil_bge -714 +1388 @cil_bgt -752 +1461 @cil_ble -2386 +4636 @cil_blt -4078 +7924 @cil_bne_un -3720 +7227 @cil_bge_un -140 +142 @cil_bgt_un -355 +691 @cil_ble_un -566 +1100 @cil_blt_un -92 +180 @cil_switch -12275 +23851 @cil_ldind_i1 -75 +88 @cil_ldind_u1 -3165 +5503 @cil_ldind_i2 -263 +511 @cil_ldind_u2 -2123 +2496 @cil_ldind_i4 -5026 +9765 @cil_ldind_u4 -762 +1480 @cil_ldind_i8 -1012 +1967 @cil_ldind_i -212 +249 @cil_ldind_r4 -360 +701 @cil_ldind_r8 -135 +263 @cil_ldind_ref -3421 +6648 @cil_stind_ref -8706 +16915 @cil_stind_i1 -4381 +8513 @cil_stind_i2 -1195 +1405 @cil_stind_i4 -5705 +10350 @cil_stind_i8 -1205 +2342 @cil_stind_r4 -105 +185 @cil_stind_r8 -115 +224 @cil_add -115141 +223711 @cil_sub -43842 +85181 @cil_mul -15396 +29915 @cil_div -4690 +9112 @cil_div_un -194 +253 @cil_rem -1752 +3404 @cil_rem_un -117 +228 @cil_and -30503 +59265 @cil_or -11386 +22122 @cil_xor -11676 +22687 @cil_shl -9751 +18946 @cil_shr -4717 +9166 @cil_shr_un -13421 +26077 @cil_neg -1200 +2333 @cil_not -749 +1456 @cil_conv_i1 -711 +1383 @cil_conv_i2 -744 +1446 @cil_conv_i4 -30731 +59708 @cil_conv_i8 -25852 +50230 @cil_conv_r4 -1268 +2464 @cil_conv_r8 -2714 +5274 @cil_conv_u4 -4025 +7822 @cil_conv_u8 -10047 +19521 @cil_callvirt -1054079 +2047997 @cil_cpobj @@ -1473,27 +1473,27 @@ @cil_ldobj -6505 +12639 @cil_ldstr -476424 +925656 @cil_newobj -337788 +656298 @cil_castclass -49901 +96954 @cil_isinst -29019 +56382 @cil_conv_r_un -135 +263 @cil_unbox @@ -1501,59 +1501,59 @@ @cil_throw -271796 +380778 @cil_ldfld -861960 +1674725 @cil_ldflda -154586 +300350 @cil_stfld -551659 +1071833 @cil_ldsfld -209405 +406860 @cil_ldsflda -1301 +2527 @cil_stsfld -67303 +130765 @cil_stobj -3609 +7013 @cil_conv_ovf_i1_un -10 +19 @cil_conv_ovf_i2_un -7 +14 @cil_conv_ovf_i4_un -87 +170 @cil_conv_ovf_i8_un -15 +29 @cil_conv_ovf_u1_un -10 +19 @cil_conv_ovf_u2_un -5 +9 @cil_conv_ovf_u4_un @@ -1565,7 +1565,7 @@ @cil_conv_ovf_i_un -67 +131 @cil_conv_ovf_u_un @@ -1573,139 +1573,139 @@ @cil_box -41044 +79746 @cil_newarr -57634 +111979 @cil_ldlen -28445 +55266 @cil_ldelema -5073 +9858 @cil_ldelem_i1 -90 +175 @cil_ldelem_u1 -8006 +15556 @cil_ldelem_i2 -220 +428 @cil_ldelem_u2 -3131 +6083 @cil_ldelem_i4 -9039 +17563 @cil_ldelem_u4 -9826 +19092 @cil_ldelem_i8 -6129 +11908 @cil_ldelem_i -7 +14 @cil_ldelem_r4 -145 +282 @cil_ldelem_r8 -235 +457 @cil_ldelem_ref -15783 +30665 @cil_stelem_i -11 +14 @cil_stelem_i1 -4519 +8781 @cil_stelem_i2 -4620 +8976 @cil_stelem_i4 -11734 +22799 @cil_stelem_i8 -4845 +9414 @cil_stelem_r4 -102 +199 @cil_stelem_r8 -245 +477 @cil_stelem_ref -186586 +362523 @cil_ldelem -1170 +2274 @cil_stelem -27565 +53557 @cil_unbox_any -7397 +14373 @cil_conv_ovf_i1 -12 +24 @cil_conv_ovf_u1 -57 +112 @cil_conv_ovf_i2 -40 +77 @cil_conv_ovf_u2 -27 +53 @cil_conv_ovf_i4 -147 +287 @cil_conv_ovf_u4 -40 +77 @cil_conv_ovf_i8 -7 +14 @cil_conv_ovf_u8 -23 +29 @cil_refanyval @@ -1721,23 +1721,23 @@ @cil_ldtoken -36662 +71232 @cil_conv_u2 -2231 +4334 @cil_conv_u1 -5788 +11246 @cil_conv_i -3181 +3740 @cil_conv_ovf_i -137 +267 @cil_conv_ovf_u @@ -1745,47 +1745,47 @@ @cil_add_ovf -889 +1729 @cil_add_ovf_un -77 +150 @cil_mul_ovf -228 +443 @cil_mul_ovf_un -195 +253 @cil_sub_ovf -571 +1110 @cil_sub_ovf_un -15 +29 @cil_endfinally -29252 +56834 @cil_leave -34373 +66785 @cil_leave_s -76776 +149171 @cil_stind_i -108 +127 @cil_conv_u -5046 +5932 @cil_arglist @@ -1793,31 +1793,31 @@ @cil_ceq -84249 +99035 @cil_cgt -10049 +11813 @cil_cgt_un -31892 +37489 @cil_clt -16960 +19937 @cil_clt_un -1141 +1341 @cil_ldftn -41092 +79838 @cil_ldvirtftn -571 +1110 @cil_ldarg @@ -1845,11 +1845,11 @@ @cil_localloc -849 +999 @cil_endfilter -416 +808 @cil_unaligned @@ -1857,7 +1857,7 @@ @cil_volatile -4389 +8528 @cil_tail @@ -1865,27 +1865,27 @@ @cil_initobj -52322 +101659 @cil_constrained -13012 +25283 @cil_cpblk -10 +19 @cil_initblk -2 +4 @cil_rethrow -1937 +3764 @cil_sizeof -889 +1729 @cil_refanytype @@ -1893,23 +1893,23 @@ @cil_readonly -17 +34 @cil_valueorreftype -306365 +595245 @cil_typeparameter -95089 +184751 @cil_array_type -7292 +14168 @cil_pointer_type -308 +599 @cil_function_pointer_type @@ -1917,64 +1917,64 @@ @cil_method -1189816 +2311725 @cil_method_implementation -888189 +1725686 @cil_field -518960 +1008300 @cil_parameter -2339980 +4546408 @cil_property -195525 +379891 @cil_event -10726 +20841 @cil_local_variable -592197 +1150595 @cil_catch_handler -22546 +43806 @cil_filter_handler -416 +808 @cil_finally_handler -28495 +55364 @cil_fault_handler -757 +1470 @cil_attribute -168950 +328258 compilations -564 +1095 id -564 +1095 cwd -403 +784 @@ -1988,7 +1988,7 @@ 1 2 -564 +1095 @@ -2004,12 +2004,12 @@ 1 2 -243 +472 2 3 -160 +311 @@ -2019,19 +2019,19 @@ compilation_args -2524 +4953 id -564 +1095 num -12 +24 arg -576 +1120 @@ -2045,12 +2045,12 @@ 4 5 -295 +526 5 6 -268 +569 @@ -2066,12 +2066,12 @@ 4 5 -295 +526 5 6 -268 +569 @@ -2085,14 +2085,14 @@ 12 -107 -108 -2 +117 +118 +4 225 226 -10 +19 @@ -2108,17 +2108,17 @@ 2 3 -7 +14 -107 -108 -2 +109 +110 +4 -119 -120 -2 +117 +118 +4 @@ -2134,12 +2134,12 @@ 1 2 -564 +1095 -107 +108 226 -12 +24 @@ -2155,12 +2155,12 @@ 1 2 -571 +1110 2 3 -5 +9 @@ -2170,19 +2170,19 @@ compilation_compiling_files -12395 +22584 id -548 +1095 num -1435 +711 file -10384 +22580 @@ -2194,49 +2194,74 @@ 12 +1 +3 +48 + + 3 4 -1 +58 4 5 -155 +82 5 6 -151 +87 6 7 -36 +68 7 -10 -43 +9 +97 -10 +9 +12 +87 + + +12 +15 +82 + + +15 17 -41 +82 17 -31 -41 +21 +82 -31 -59 -41 +21 +27 +87 -59 -1359 -36 +28 +37 +82 + + +37 +65 +82 + + +67 +147 +63 @@ -2250,49 +2275,74 @@ 12 +1 +3 +48 + + 3 4 -1 +58 4 5 -155 +82 5 6 -151 +87 6 7 -36 +68 7 -10 -43 +9 +97 -10 +9 +12 +87 + + +12 +15 +82 + + +15 17 -41 +82 17 -31 -41 +21 +82 -31 -59 -41 +21 +27 +87 -59 -1359 -36 +28 +37 +82 + + +37 +65 +82 + + +67 +147 +63 @@ -2307,28 +2357,73 @@ 1 -2 -739 - - -2 3 -411 +43 3 -17 -118 +4 +29 -17 -38 -108 +4 +5 +58 + + +5 +6 +9 + + +6 +7 +97 + + +7 +11 +53 + + +11 +12 +77 + + +12 +18 +63 + + +18 +24 +53 + + +25 +33 +53 38 -520 -57 +52 +53 + + +56 +103 +53 + + +108 +216 +53 + + +217 +226 +9 @@ -2343,29 +2438,74 @@ 1 -2 -739 - - -2 3 -411 +43 3 -16 -116 +4 +29 -16 -36 -109 - - -36 -476 +4 +5 58 + +5 +6 +9 + + +6 +7 +97 + + +7 +11 +53 + + +11 +12 +77 + + +12 +18 +63 + + +18 +24 +53 + + +25 +33 +53 + + +38 +52 +53 + + +56 +103 +53 + + +108 +216 +53 + + +217 +226 +9 + @@ -2380,17 +2520,12 @@ 1 2 -9343 +22575 2 3 -822 - - -3 -187 -218 +4 @@ -2406,12 +2541,12 @@ 1 2 -9831 +22575 2 -78 -552 +3 +4 @@ -2421,19 +2556,19 @@ compilation_referencing_files -184906 +359260 id -564 +1095 num -1411 +2742 file -1757 +3414 @@ -2447,67 +2582,67 @@ 5 284 -47 +92 284 288 -45 +87 288 292 -47 +92 293 309 -45 +87 309 311 -47 +92 311 328 -42 +82 328 344 -37 +73 344 346 -50 +97 346 349 -45 +87 349 353 -45 +87 353 359 -47 +92 359 369 -42 +82 369 564 -20 +38 @@ -2523,67 +2658,67 @@ 5 284 -47 +92 284 288 -45 +87 288 292 -47 +92 293 309 -45 +87 309 311 -47 +92 311 328 -42 +82 328 344 -37 +73 344 346 -50 +97 346 349 -45 +87 349 353 -45 +87 353 359 -47 +92 359 369 -42 +82 369 564 -20 +38 @@ -2599,42 +2734,42 @@ 1 4 -112 +219 4 7 -15 +29 7 8 -358 +696 8 118 -112 +219 118 214 -105 +204 222 223 -328 +638 224 225 -365 +711 225 226 -12 +24 @@ -2650,62 +2785,62 @@ 1 4 -112 +219 4 5 -5 +9 5 6 -338 +594 6 -20 -125 +17 +209 -20 -27 -115 +17 +23 +233 -27 -32 -122 +23 +31 +219 -32 -38 -112 +31 +35 +228 -38 -50 -107 +35 +45 +228 -50 -60 -112 +45 +57 +209 -60 +57 62 -100 +189 62 65 -110 +224 65 -71 -47 +73 +175 @@ -2721,57 +2856,57 @@ 1 2 -270 +526 2 5 -132 +258 6 7 -2 +4 7 8 -162 +316 8 10 -142 +277 10 23 -132 +258 23 122 -132 +258 124 214 -125 +243 220 221 -37 +73 222 223 -248 +482 224 225 -368 +715 @@ -2787,67 +2922,62 @@ 1 2 -290 +560 2 5 -155 +282 5 6 -95 +194 6 7 -155 +267 7 11 -135 +282 11 20 -137 +272 20 25 -132 +272 25 29 -135 +258 29 -48 -132 +45 +267 -49 -62 -120 +47 +63 +272 -62 -64 -105 +63 +67 +306 -64 -68 -150 - - -68 -72 -10 +67 +74 +175 @@ -2857,23 +2987,23 @@ compilation_time -3948 +7671 id -564 +1095 num -2 +4 kind -17 +34 seconds -2862 +5688 @@ -2887,7 +3017,7 @@ 1 2 -564 +1095 @@ -2903,7 +3033,7 @@ 7 8 -564 +1095 @@ -2917,14 +3047,9 @@ 12 -6 -7 -2 - - 7 8 -561 +1095 @@ -2940,7 +3065,7 @@ 225 226 -2 +4 @@ -2956,7 +3081,7 @@ 7 8 -2 +4 @@ -2970,9 +3095,9 @@ 12 -1142 -1143 -2 +1168 +1169 +4 @@ -2988,7 +3113,7 @@ 225 226 -17 +34 @@ -3004,7 +3129,7 @@ 1 2 -17 +34 @@ -3018,24 +3143,34 @@ 12 -158 -159 -2 +171 +172 +4 -161 -162 -2 +175 +176 +4 -174 -175 -5 +180 +181 +4 + + +182 +183 +4 + + +224 +225 +4 225 226 -7 +9 @@ -3051,64 +3186,64 @@ 1 2 -2243 +4490 2 3 -353 - - -3 -6 -248 - - -6 -9 -17 - - - - - - -seconds -num - - -12 - - -1 -2 -2862 - - - - - - -seconds -kind - - -12 - - -1 -2 -2436 - - -2 -3 -353 +691 3 5 -72 +443 + + +5 +7 +63 + + + + + + +seconds +num + + +12 + + +1 +2 +5688 + + + + + + +seconds +kind + + +12 + + +1 +2 +4812 + + +2 +3 +725 + + +3 +5 +150 @@ -4351,11 +4486,11 @@ extractor_messages -750 +7638 id -750 +7638 severity @@ -4367,19 +4502,19 @@ text -11 +12 entity -541 +5272 location -622 +6707 stack_trace -121 +202 @@ -4393,7 +4528,7 @@ 1 2 -750 +7638 @@ -4409,7 +4544,7 @@ 1 2 -750 +7638 @@ -4425,7 +4560,7 @@ 1 2 -750 +7638 @@ -4441,7 +4576,7 @@ 1 2 -750 +7638 @@ -4457,7 +4592,7 @@ 1 2 -750 +7638 @@ -4473,7 +4608,7 @@ 1 2 -750 +7638 @@ -4492,13 +4627,13 @@ 1 -24 -25 +49 +50 1 -721 -722 +7584 +7585 1 @@ -4531,7 +4666,12 @@ 1 2 -2 +1 + + +2 +3 +1 9 @@ -4555,13 +4695,13 @@ 1 -5 -6 +6 +7 1 -535 -536 +5267 +5268 1 @@ -4581,13 +4721,13 @@ 1 -12 -13 +37 +38 1 -610 -611 +6670 +6671 1 @@ -4607,8 +4747,8 @@ 2 -120 -121 +201 +202 1 @@ -4623,8 +4763,8 @@ 12 -750 -751 +7638 +7639 1 @@ -4655,8 +4795,8 @@ 12 -11 -12 +12 +13 1 @@ -4671,8 +4811,8 @@ 12 -541 -542 +5272 +5273 1 @@ -4687,8 +4827,8 @@ 12 -622 -623 +6707 +6708 1 @@ -4703,8 +4843,8 @@ 12 -121 -122 +202 +203 1 @@ -4724,23 +4864,13 @@ 1 -3 -4 -1 - - 5 6 1 -16 -17 -1 - - -19 -20 +11 +12 1 @@ -4749,23 +4879,38 @@ 2 -30 -31 +25 +26 1 -49 -50 +38 +39 1 -244 -245 +104 +105 1 -334 -335 +216 +217 +1 + + +326 +327 +1 + + +2412 +2413 +1 + + +4451 +4452 1 @@ -4782,7 +4927,7 @@ 1 2 -11 +12 @@ -4798,7 +4943,7 @@ 1 2 -11 +12 @@ -4814,12 +4959,7 @@ 1 2 -3 - - -3 -4 -1 +4 5 @@ -4827,11 +4967,6 @@ 1 -8 -9 -1 - - 11 12 1 @@ -4842,18 +4977,28 @@ 1 -20 -21 +47 +48 1 -189 -190 +51 +52 1 -284 -285 +275 +276 +1 + + +1648 +1649 +1 + + +3224 +3225 1 @@ -4873,13 +5018,8 @@ 3 -3 -4 -1 - - -8 -9 +11 +12 1 @@ -4893,23 +5033,33 @@ 1 -26 -27 +25 +26 1 -30 -31 +104 +105 1 -216 -217 +113 +114 1 -306 -307 +326 +327 +1 + + +2018 +2019 +1 + + +4077 +4078 1 @@ -4931,21 +5081,21 @@ 3 4 +3 + + +10 +11 1 -4 -5 -2 - - -34 -35 +55 +56 1 -71 -72 +124 +125 1 @@ -4962,17 +5112,17 @@ 1 2 -425 +4192 2 3 -92 +792 3 -25 -24 +133 +288 @@ -4988,7 +5138,12 @@ 1 2 -541 +5271 + + +3 +4 +1 @@ -5004,7 +5159,7 @@ 1 2 -541 +5272 @@ -5020,12 +5175,12 @@ 1 2 -540 +5262 2 -3 -1 +5 +10 @@ -5041,17 +5196,17 @@ 1 2 -490 +4587 2 -4 -47 +3 +478 -4 -17 -4 +3 +67 +207 @@ -5067,12 +5222,12 @@ 1 2 -512 +5188 2 6 -29 +84 @@ -5088,12 +5243,12 @@ 1 2 -521 +5803 2 3 -100 +903 29 @@ -5114,7 +5269,7 @@ 1 2 -621 +6706 2 @@ -5135,7 +5290,7 @@ 1 2 -622 +6707 @@ -5151,7 +5306,7 @@ 1 2 -621 +6706 2 @@ -5172,12 +5327,7 @@ 1 2 -621 - - -2 -3 -1 +6707 @@ -5193,12 +5343,12 @@ 1 2 -596 +6685 2 3 -26 +22 @@ -5214,41 +5364,46 @@ 1 2 -42 +55 2 3 -22 +34 3 4 -9 +17 4 -5 -11 - - -5 6 -6 +18 6 9 -11 +18 9 -21 -10 +15 +18 -21 -76 +15 +49 +16 + + +54 +205 +16 + + +253 +1137 10 @@ -5265,7 +5420,7 @@ 1 2 -120 +201 2 @@ -5286,7 +5441,7 @@ 1 2 -121 +202 @@ -5302,11 +5457,11 @@ 1 2 -120 +201 -2 -3 +3 +4 1 @@ -5323,42 +5478,47 @@ 1 2 -55 +70 2 3 -17 +28 3 4 -10 +22 4 -5 -8 - - -5 6 -6 +16 6 -9 -11 +8 +15 -9 -21 -10 +8 +15 +17 -25 -76 -4 +15 +55 +16 + + +57 +403 +16 + + +571 +917 +2 @@ -5374,43 +5534,48 @@ 1 2 -50 +63 2 3 -18 +31 3 4 -8 +19 4 5 -10 +12 5 -6 -6 +8 +17 -6 -9 +8 +13 +17 + + +13 +37 +16 + + +38 +158 +16 + + +162 +1137 11 - -9 -19 -10 - - -20 -76 -8 - @@ -5419,19 +5584,19 @@ compilation_finished -564 +1095 id -564 +1095 cpu_seconds -501 +998 elapsed_seconds -564 +1095 @@ -5445,7 +5610,7 @@ 1 2 -564 +1095 @@ -5461,7 +5626,7 @@ 1 2 -564 +1095 @@ -5477,17 +5642,12 @@ 1 2 -448 +901 2 3 -47 - - -3 -6 -5 +97 @@ -5503,17 +5663,12 @@ 1 2 -448 +901 2 3 -47 - - -3 -6 -5 +97 @@ -5529,7 +5684,7 @@ 1 2 -564 +1095 @@ -5545,7 +5700,7 @@ 1 2 -564 +1095 @@ -5555,15 +5710,15 @@ compilation_assembly -564 +1095 id -564 +1095 assembly -564 +1095 @@ -5577,7 +5732,7 @@ 1 2 -564 +1095 @@ -5593,7 +5748,7 @@ 1 2 -564 +1095 @@ -6017,23 +6172,23 @@ externalData -30 +58 id -15 +29 path -2 +4 column -5 +9 value -30 +58 @@ -6047,7 +6202,7 @@ 1 2 -15 +29 @@ -6063,7 +6218,7 @@ 2 3 -15 +29 @@ -6079,7 +6234,7 @@ 2 3 -15 +29 @@ -6095,7 +6250,7 @@ 6 7 -2 +4 @@ -6111,7 +6266,7 @@ 2 3 -2 +4 @@ -6127,7 +6282,7 @@ 12 13 -2 +4 @@ -6143,7 +6298,7 @@ 6 7 -5 +9 @@ -6159,7 +6314,7 @@ 1 2 -5 +9 @@ -6175,7 +6330,7 @@ 6 7 -5 +9 @@ -6191,7 +6346,7 @@ 1 2 -30 +58 @@ -6207,7 +6362,7 @@ 1 2 -30 +58 @@ -6223,7 +6378,7 @@ 1 2 -30 +58 @@ -6233,41 +6388,41 @@ snapshotDate -2 +4 snapshotDate -2 +4 sourceLocationPrefix -2 +4 prefix -2 +4 duplicateCode -11701 +22735 id -11701 +22735 relativePath -1957 +3803 equivClass -3607 +7008 @@ -6281,7 +6436,7 @@ 1 2 -11701 +22735 @@ -6297,7 +6452,7 @@ 1 2 -11701 +22735 @@ -6313,52 +6468,52 @@ 1 2 -546 +1061 2 3 -290 +564 3 4 -218 +423 4 5 -112 +219 5 6 -112 +219 6 8 -172 +336 8 10 -142 +277 10 14 -162 +316 14 28 -147 +287 29 77 -50 +97 @@ -6374,52 +6529,52 @@ 1 2 -581 +1129 2 3 -268 +521 3 4 -228 +443 4 5 -120 +233 5 6 -117 +228 6 8 -167 +326 8 10 -142 +277 10 14 -160 +311 14 32 -150 +292 33 45 -20 +38 @@ -6435,32 +6590,32 @@ 2 3 -1937 +3764 3 4 -589 +1144 4 5 -403 +784 5 6 -220 +428 6 8 -293 +569 8 11 -162 +316 @@ -6476,37 +6631,37 @@ 1 2 -348 +677 2 3 -1769 +3438 3 4 -554 +1076 4 5 -348 +677 5 6 -198 +384 6 9 -298 +579 9 11 -90 +175 @@ -8584,11 +8739,11 @@ locations_default -11326677 +14080010 id -11326677 +14080010 file @@ -8596,19 +8751,19 @@ beginLine -157416 +164761 beginColumn -1453 +1456 endLine -175851 +177711 endColumn -1620 +1641 @@ -8622,7 +8777,7 @@ 1 2 -11326677 +14080010 @@ -8638,7 +8793,7 @@ 1 2 -11326677 +14080010 @@ -8654,7 +8809,7 @@ 1 2 -11326677 +14080010 @@ -8670,7 +8825,7 @@ 1 2 -11326677 +14080010 @@ -8686,7 +8841,7 @@ 1 2 -11326677 +14080010 @@ -8701,73 +8856,73 @@ 1 -5 -420 +19 +472 -5 -7 -419 +19 +34 +470 -7 -9 -444 +34 +50 +497 -9 -12 -461 +50 +74 +468 -12 -17 -496 +74 +106 +473 -17 -28 -488 +106 +150 +476 -28 -45 -515 +150 +208 +476 -45 -76 -474 +208 +297 +473 -76 -129 +297 +446 469 -129 -218 +446 +687 468 -218 -424 +687 +1204 468 -424 -1086 +1204 +2639 468 -1087 -28809 -468 +2639 +42820 +494 -31722 +43087 474768 -174 +60 @@ -8782,68 +8937,68 @@ 1 -5 -569 +12 +541 -5 -7 -499 - - -7 -9 -447 - - -9 -11 -392 - - -11 -14 -504 - - -14 +12 19 -521 +506 19 -28 -533 +27 +519 -28 -40 -488 +27 +35 +494 -40 -60 -480 +35 +46 +512 -60 -94 +46 +61 +474 + + +61 +82 +504 + + +82 +114 +477 + + +114 +168 475 -94 -205 -469 - - -205 -658 +168 +273 468 -662 +273 +504 +486 + + +504 +1742 +468 + + +1746 143014 -387 +308 @@ -8858,68 +9013,68 @@ 1 -3 -143 +7 +563 -3 -4 -606 - - -4 -5 -675 - - -5 -6 -461 - - -6 -8 -533 - - -8 +7 13 -535 +499 13 -20 -535 - - -20 -30 +19 486 -30 +19 +26 +486 + + +26 +34 +511 + + +34 43 -500 +498 43 -59 -479 +53 +484 -59 -82 -474 +53 +64 +481 -82 -127 -469 +64 +76 +481 -127 +76 +91 +476 + + +91 +112 +477 + + +112 +166 +473 + + +166 930 -336 +317 @@ -8934,68 +9089,73 @@ 1 -5 -561 - - -5 -7 -504 - - -7 -9 -449 - - -9 12 -546 +480 12 -16 -573 +18 +476 -16 -22 -499 +18 +25 +481 -22 -33 -489 +25 +34 +496 -33 -46 -489 - - -46 -73 -484 - - -73 -129 -487 - - -129 -326 +34 +44 468 -326 -2738 +44 +56 +483 + + +56 +76 +473 + + +76 +104 +478 + + +104 +146 +469 + + +146 +230 468 -2749 +230 +405 +468 + + +405 +840 +468 + + +845 +28774 +472 + + +46287 171760 -215 +52 @@ -9010,68 +9170,68 @@ 1 -5 -442 - - -5 -7 -534 - - -7 -9 -416 - - -9 -12 -536 - - -12 -16 -469 - - -16 -23 -499 - - -23 -34 -498 - - -34 -48 -470 - - -48 -64 -482 - - -64 -82 +15 475 -82 -109 -472 +15 +23 +481 -109 -161 -485 +23 +33 +519 -161 +33 +44 +503 + + +44 +54 +481 + + +54 +66 +490 + + +66 +77 +480 + + +77 +91 +474 + + +91 +105 +490 + + +105 +123 +491 + + +123 +148 +470 + + +148 +186 +473 + + +186 1038 -454 +405 @@ -9087,57 +9247,62 @@ 1 2 -2678 +4162 2 3 -41791 +30681 3 4 -15680 +15896 4 5 -16871 +16240 5 6 -8775 +9901 6 -9 -12511 +8 +13417 -9 -99 -11909 +8 +13 +13925 -99 -109 -11941 +13 +101 +14154 -109 -164 -11942 +101 +117 +12389 -164 -250 -11862 +117 +182 +12558 -250 -7392 -11456 +182 +301 +12385 + + +301 +10809 +9053 @@ -9153,42 +9318,37 @@ 1 2 -92520 +72389 2 -18 -11816 +3 +30310 -18 -50 -6689 +3 +38 +12534 -50 -51 -10035 +38 +52 +14356 -51 -65 -12205 +52 +79 +12462 -65 -105 -12183 +79 +118 +12565 -105 -708 -11807 - - -709 -5267 -161 +118 +6166 +10145 @@ -9204,52 +9364,57 @@ 1 2 -28742 +23471 2 3 -36135 +30016 3 4 -6197 +11007 4 5 -27310 +22185 5 6 -6023 +10197 6 7 -11735 +11740 7 -10 -13098 +9 +13756 -10 -16 -12302 +9 +12 +13097 -16 -48 -11897 +12 +19 +12777 -48 -335 -3977 +19 +66 +12384 + + +66 +352 +4131 @@ -9265,27 +9430,32 @@ 1 2 -72276 +67387 2 3 -48541 +51814 3 4 -14456 +18654 4 6 -12667 +13928 6 +34 +12361 + + +34 306 -9476 +617 @@ -9301,57 +9471,62 @@ 1 2 -2731 +4192 2 3 -43580 +31624 3 4 -16640 +16670 4 5 -20845 +18713 5 6 -11859 +12088 6 7 -9405 +10186 7 9 -11941 +14626 9 -14 -13283 +12 +14505 -14 -24 -12004 +12 +17 +13374 -24 -94 -11811 +17 +29 +12447 -94 -378 -3317 +29 +111 +12416 + + +111 +389 +3920 @@ -9367,22 +9542,22 @@ 1 2 -351 +352 2 3 -185 +184 3 4 -100 +101 4 6 -128 +129 6 @@ -9391,33 +9566,33 @@ 13 -39 -109 +40 +111 -39 -106 -109 +40 +110 +111 -106 -392 -109 +112 +476 +110 -400 -3801 -109 +490 +5418 +110 -4033 -35252 -109 +5447 +74992 +110 -37256 -1800792 -30 +76227 +2221388 +24 @@ -9433,17 +9608,17 @@ 1 2 -481 +482 2 3 -188 +187 3 4 -113 +115 4 @@ -9453,31 +9628,31 @@ 6 11 -117 +115 11 -59 +58 110 -59 -177 -109 +58 +194 +110 -177 -695 -109 +195 +1098 +110 -698 -2521 -109 +1112 +3852 +110 -2548 -6053 +3882 +6231 8 @@ -9504,12 +9679,12 @@ 3 4 -112 +114 4 7 -109 +110 7 @@ -9518,28 +9693,28 @@ 18 -53 -111 +54 +113 -53 -128 -109 +54 +139 +110 -128 -585 -109 +140 +803 +110 -602 -4407 -109 +804 +6771 +110 -4493 +6786 116262 -84 +79 @@ -9565,12 +9740,12 @@ 3 4 -112 +114 4 7 -109 +110 7 @@ -9579,28 +9754,28 @@ 18 -53 -111 +54 +113 -53 -129 -109 +54 +139 +110 -129 -586 -109 +140 +797 +110 -603 -4408 -109 +803 +6771 +110 -4493 -124735 -84 +6783 +124736 +79 @@ -9616,17 +9791,17 @@ 1 2 -422 +423 2 3 -230 +229 3 4 -93 +96 4 @@ -9640,28 +9815,28 @@ 12 -24 -112 +25 +114 -24 -48 +25 +53 110 -48 -103 -109 +53 +108 +111 -103 -176 -110 +108 +204 +111 -176 -724 -43 +204 +727 +38 @@ -9677,57 +9852,62 @@ 1 2 -43052 +30736 2 3 -15495 +14517 3 4 -16141 +16816 4 5 -11843 +12515 5 -7 -15117 +6 +10358 -7 +6 +9 +14907 + + +9 51 -13292 +14737 51 -67 -13277 +64 +13404 -67 -108 -13666 +64 +109 +13430 -108 +109 170 -13281 +13424 170 -273 -13192 +277 +13375 -273 -6927 -7495 +277 +10708 +9492 @@ -9743,37 +9923,37 @@ 1 2 -102373 +74587 2 -50 -10686 +3 +32293 -50 +3 51 -14316 +15351 51 -61 -13298 +53 +14842 -61 -105 -13198 +53 +91 +13579 -105 -140 -13318 +91 +136 +14119 -140 -5438 -8662 +136 +5796 +12940 @@ -9789,27 +9969,27 @@ 1 2 -108963 +94269 2 3 -30801 +38080 3 4 -14008 +18054 4 -7 -15017 +6 +14148 -7 -50 -7062 +6 +61 +13160 @@ -9825,52 +10005,57 @@ 1 2 -44241 +31573 2 3 -33451 +28818 3 4 -9654 +12789 4 5 -22023 +19691 5 6 -9633 +11849 6 7 -10956 +11679 7 -10 -15510 +9 +15126 -10 -16 -13744 +9 +12 +14464 -16 -55 -13266 +12 +18 +13367 -55 -334 -3373 +18 +58 +13376 + + +58 +353 +4979 @@ -9886,57 +10071,62 @@ 1 2 -43633 +31276 2 3 -19238 +18345 3 4 -20512 +19308 4 5 -15969 +15250 5 6 -14483 +13460 6 7 -8953 +9784 7 9 -12318 +14539 9 -14 +12 13943 -14 -27 -13475 +12 +17 +13348 -27 -206 -13190 +17 +32 +13514 -206 -378 -137 +32 +156 +13329 + + +156 +388 +1615 @@ -9952,12 +10142,12 @@ 1 2 -393 +406 2 3 -202 +205 3 @@ -9967,42 +10157,42 @@ 4 7 -122 +126 7 51 -123 - - -51 -121 124 -121 -301 -122 +51 +122 +126 -311 -1031 -122 +122 +325 +124 -1037 -6674 -122 +328 +1118 +124 -6754 -56985 -122 +1126 +9603 +124 -57295 -866412 -52 +9620 +82632 +124 + + +82696 +908740 +42 @@ -10018,52 +10208,52 @@ 1 2 -507 +521 2 3 -182 +186 3 4 -120 +119 4 9 -127 +130 9 -61 -125 +62 +132 -61 -124 -123 +62 +128 +127 -124 -205 -122 +129 +222 +124 -206 -441 -122 +222 +710 +124 -441 -1921 -122 +717 +3690 +124 -1944 -4225 -70 +3701 +5368 +54 @@ -10079,12 +10269,12 @@ 1 2 -400 +414 2 3 -209 +211 3 @@ -10094,42 +10284,42 @@ 4 6 -123 +127 6 14 -130 +131 14 -43 -123 +44 +125 -43 -120 -123 +44 +124 +124 -121 -466 -122 +126 +541 +124 -471 -4055 -122 +549 +5840 +124 -4055 -13772 -122 +6139 +19157 +124 -13909 -47532 -23 +19476 +47830 +14 @@ -10145,22 +10335,22 @@ 1 2 -502 +518 2 3 -231 +232 3 4 -95 +96 4 7 -146 +147 7 @@ -10169,28 +10359,28 @@ 16 -33 -127 - - -33 -78 -122 - - -78 -107 -122 - - -107 -151 +34 124 -151 -337 -18 +34 +83 +128 + + +83 +114 +125 + + +114 +164 +127 + + +164 +338 +11 @@ -10206,7 +10396,7 @@ 1 2 -400 +416 2 @@ -10221,42 +10411,42 @@ 4 6 -123 +127 6 14 -130 +131 14 -43 -123 +44 +125 -43 -120 -123 +44 +124 +124 -121 -466 -122 +126 +537 +124 -475 -4050 -122 +541 +5831 +124 -4064 -13686 -122 +6123 +19067 +124 -13833 -47528 -23 +19460 +47823 +14 @@ -10266,15 +10456,15 @@ locations_mapped -248620 +483051 id -248620 +483051 mapped_to -211461 +410854 @@ -10288,7 +10478,7 @@ 1 2 -248620 +483051 @@ -10304,12 +10494,12 @@ 1 2 -205510 +399291 2 119 -5951 +11562 @@ -10319,23 +10509,23 @@ numlines -4532217 +4586385 element_id -4532216 +4586378 num_lines -1349 +1354 num_code -1242 +1247 num_comment -635 +637 @@ -10349,12 +10539,12 @@ 1 2 -4532215 +4586371 2 3 -1 +7 @@ -10370,12 +10560,12 @@ 1 2 -4532215 +4586371 2 3 -1 +7 @@ -10391,7 +10581,12 @@ 1 2 -4532216 +4586374 + + +2 +3 +4 @@ -10407,37 +10602,37 @@ 1 2 -660 +651 2 3 -208 +207 3 4 -94 +97 4 -6 -94 +7 +125 -6 -12 -108 +7 +19 +105 -12 -50 -104 +19 +121 +102 -52 -1598592 -81 +126 +1600586 +67 @@ -10453,32 +10648,37 @@ 1 2 -733 +723 2 3 -198 +194 3 4 -99 +106 4 7 -121 +111 7 -15 -102 +16 +103 -15 -34 -96 +16 +35 +104 + + +35 +39 +13 @@ -10494,32 +10694,37 @@ 1 2 -733 +723 2 3 -198 +196 3 4 -97 +102 4 7 -118 +105 7 17 -109 +104 17 +32 +106 + + +32 81 -94 +18 @@ -10535,37 +10740,37 @@ 1 2 -651 +647 2 3 -149 +152 3 4 -83 +79 4 6 -99 +93 6 14 -102 +98 14 -77 -94 +50 +95 -83 -1607845 -64 +52 +1615186 +83 @@ -10581,32 +10786,37 @@ 1 2 -728 +723 2 3 -140 +143 3 4 -84 +82 4 7 -107 +100 7 -18 +19 96 -18 -42 -87 +19 +43 +94 + + +43 +49 +9 @@ -10622,32 +10832,37 @@ 1 2 -728 +723 2 3 -141 +145 3 4 -80 +77 4 7 -106 +102 7 -15 +16 +95 + + +16 +50 94 -15 -83 -93 +50 +85 +11 @@ -10668,12 +10883,12 @@ 2 3 -134 +131 3 4 -55 +56 4 @@ -10683,17 +10898,17 @@ 6 14 -50 +49 14 -178 +173 48 -178 -4511467 -14 +215 +4549896 +19 @@ -10714,32 +10929,32 @@ 2 3 -138 +135 3 4 -56 +57 4 6 -50 +51 6 -15 +16 49 -15 -119 -49 +16 +128 +48 -131 -738 -8 +136 +746 +12 @@ -10760,32 +10975,32 @@ 2 3 -139 +135 3 4 -54 +56 4 6 -51 +53 6 -15 +16 48 -15 -103 -49 +16 +117 +48 -116 -731 -9 +118 +739 +12 @@ -10795,27 +11010,27 @@ assemblies -2160 +4198 id -2160 +4198 file -2160 +4198 fullname -1769 +3438 name -1631 +3170 version -190 +370 @@ -10829,7 +11044,7 @@ 1 2 -2160 +4198 @@ -10845,7 +11060,7 @@ 1 2 -2160 +4198 @@ -10861,7 +11076,7 @@ 1 2 -2160 +4198 @@ -10877,7 +11092,7 @@ 1 2 -2160 +4198 @@ -10893,7 +11108,7 @@ 1 2 -2160 +4198 @@ -10909,7 +11124,7 @@ 1 2 -2160 +4198 @@ -10925,7 +11140,7 @@ 1 2 -2160 +4198 @@ -10941,7 +11156,7 @@ 1 2 -2160 +4198 @@ -10957,12 +11172,12 @@ 1 2 -1378 +2678 2 3 -391 +759 @@ -10978,12 +11193,12 @@ 1 2 -1378 +2678 2 3 -391 +759 @@ -10999,7 +11214,7 @@ 1 2 -1769 +3438 @@ -11015,7 +11230,7 @@ 1 2 -1769 +3438 @@ -11031,17 +11246,17 @@ 1 2 -1125 +2186 2 3 -483 +940 3 4 -22 +43 @@ -11057,17 +11272,17 @@ 1 2 -1125 +2186 2 3 -483 +940 3 4 -22 +43 @@ -11083,12 +11298,12 @@ 1 2 -1516 +2946 2 4 -115 +224 @@ -11104,12 +11319,12 @@ 1 2 -1516 +2946 2 4 -115 +224 @@ -11125,32 +11340,32 @@ 1 2 -105 +204 2 3 -27 +53 3 6 -15 +29 6 10 -17 +34 11 37 -15 +29 50 386 -10 +19 @@ -11166,32 +11381,32 @@ 1 2 -105 +204 2 3 -27 +53 3 6 -15 +29 6 10 -17 +34 11 37 -15 +29 50 386 -10 +19 @@ -11207,32 +11422,32 @@ 1 2 -107 +209 2 3 -27 +53 3 5 -12 +24 6 10 -17 +34 11 36 -15 +29 50 234 -10 +19 @@ -11248,32 +11463,32 @@ 1 2 -107 +209 2 3 -27 +53 3 5 -12 +24 6 10 -17 +34 11 36 -15 +29 50 234 -10 +19 @@ -11283,27 +11498,27 @@ files -24351 +47312 id -24351 +47312 name -24351 +47312 simple -13679 +26578 ext -22 +43 fromSource -2 +4 @@ -11317,7 +11532,7 @@ 1 2 -24351 +47312 @@ -11333,7 +11548,7 @@ 1 2 -24351 +47312 @@ -11349,7 +11564,7 @@ 1 2 -24351 +47312 @@ -11365,7 +11580,7 @@ 1 2 -24351 +47312 @@ -11381,7 +11596,7 @@ 1 2 -24351 +47312 @@ -11397,7 +11612,7 @@ 1 2 -24351 +47312 @@ -11413,7 +11628,7 @@ 1 2 -24351 +47312 @@ -11429,7 +11644,7 @@ 1 2 -24351 +47312 @@ -11445,12 +11660,12 @@ 1 2 -12787 +24844 2 154 -892 +1733 @@ -11466,12 +11681,12 @@ 1 2 -12787 +24844 2 154 -892 +1733 @@ -11487,12 +11702,12 @@ 1 2 -13168 +25585 2 5 -511 +993 @@ -11508,7 +11723,7 @@ 1 2 -13679 +26578 @@ -11524,47 +11739,47 @@ 1 2 -2 +4 2 3 -2 +4 6 7 -2 +4 166 167 -2 +4 173 174 -2 +4 861 862 -2 +4 995 996 -2 +4 2875 2876 -2 +4 4635 4636 -2 +4 @@ -11580,47 +11795,47 @@ 1 2 -2 +4 2 3 -2 +4 6 7 -2 +4 166 167 -2 +4 173 174 -2 +4 861 862 -2 +4 995 996 -2 +4 2875 2876 -2 +4 4635 4636 -2 +4 @@ -11636,42 +11851,42 @@ 1 2 -2 +4 2 3 -5 +9 166 167 -2 +4 169 170 -2 +4 214 215 -2 +4 650 651 -2 +4 790 791 -2 +4 3818 3819 -2 +4 @@ -11687,7 +11902,7 @@ 1 2 -22 +43 @@ -11703,7 +11918,7 @@ 9714 9715 -2 +4 @@ -11719,7 +11934,7 @@ 9714 9715 -2 +4 @@ -11735,7 +11950,7 @@ 5457 5458 -2 +4 @@ -11751,7 +11966,7 @@ 9 10 -2 +4 @@ -11761,19 +11976,19 @@ folders -9177 +17831 id -9177 +17831 name -8036 +15615 simple -1428 +2776 @@ -11787,7 +12002,7 @@ 1 2 -9177 +17831 @@ -11803,7 +12018,7 @@ 1 2 -9177 +17831 @@ -11819,7 +12034,7 @@ 1 2 -8036 +15615 @@ -11835,12 +12050,12 @@ 1 2 -6896 +13399 2 3 -1140 +2216 @@ -11856,27 +12071,27 @@ 1 2 -842 +1636 2 3 -278 +540 3 4 -107 +209 4 10 -107 +209 10 383 -92 +180 @@ -11892,27 +12107,27 @@ 1 2 -842 +1636 2 3 -278 +540 3 4 -107 +209 4 10 -107 +209 10 383 -92 +180 @@ -11922,15 +12137,15 @@ containerparent -32383 +62918 parent -8036 +15615 child -32383 +62918 @@ -11944,37 +12159,37 @@ 1 2 -4356 +8465 2 3 -1070 +2079 3 4 -486 +944 4 5 -541 +1052 5 9 -629 +1222 9 17 -609 +1183 17 170 -343 +667 @@ -11990,7 +12205,7 @@ 1 2 -32383 +62918 @@ -12000,15 +12215,15 @@ file_extraction_mode -16276 +31624 file -16276 +31624 mode -2 +4 @@ -12022,7 +12237,7 @@ 1 2 -16276 +31624 @@ -12038,7 +12253,7 @@ 6493 6494 -2 +4 @@ -12048,15 +12263,15 @@ namespaces -11293 +21942 id -11293 +21942 name -2516 +4890 @@ -12070,7 +12285,7 @@ 1 2 -11293 +21942 @@ -12086,37 +12301,37 @@ 1 2 -7 +14 2 3 -1797 +3492 3 4 -2 +4 4 5 -320 +623 6 10 -190 +370 10 101 -190 +370 110 139 -7 +14 @@ -12126,15 +12341,15 @@ namespace_declarations -8355 +19760 id -8355 +19760 namespace_id -1774 +3886 @@ -12148,7 +12363,7 @@ 1 2 -8355 +19760 @@ -12164,37 +12379,42 @@ 1 2 -669 +1397 2 3 -406 +798 3 4 -175 +414 4 5 -140 +306 5 6 -110 +224 6 9 -140 +331 9 +17 +301 + + +17 996 -132 +112 @@ -12204,15 +12424,15 @@ namespace_declaration_location -8355 +19760 id -8355 +19760 loc -8355 +19760 @@ -12226,7 +12446,7 @@ 1 2 -8355 +19760 @@ -12242,7 +12462,7 @@ 1 2 -8355 +19760 @@ -12252,15 +12472,15 @@ parent_namespace -388662 +777059 child_id -388662 +777059 namespace_id -6974 +13554 @@ -12274,7 +12494,7 @@ 1 2 -388662 +777059 @@ -12290,57 +12510,57 @@ 1 2 -1709 +3326 2 3 -842 +1626 3 4 -531 +1027 4 5 -468 +915 5 7 -641 +1251 7 10 -561 +1091 10 15 -589 +1139 15 23 -546 +1061 23 51 -523 +1027 51 835 -523 +1017 900 -34743 -35 +35556 +68 @@ -12350,15 +12570,15 @@ parent_namespace_declaration -43445 +88303 child_id -43212 +87787 namespace_id -8355 +19760 @@ -12372,12 +12592,12 @@ 1 2 -43145 +87636 2 60 -67 +150 @@ -12393,32 +12613,32 @@ 1 2 -5412 +13778 2 9 -747 +1714 9 13 -656 +1276 13 16 -734 +1427 16 -21 -508 +32 +1509 -31 +32 33 -295 +53 @@ -12428,15 +12648,15 @@ using_namespace_directives -66100 +144252 id -66100 +144252 namespace_id -1990 +4227 @@ -12450,7 +12670,7 @@ 1 2 -66100 +144252 @@ -12466,47 +12686,52 @@ 1 2 -696 +1495 2 3 -285 +472 3 4 -115 +297 4 -6 -182 +5 +238 -6 -11 -177 +5 +8 +365 -11 -21 -177 +8 +14 +336 -21 -45 -152 +14 +25 +321 -48 -206 -150 +25 +63 +326 -214 -2199 -50 +64 +465 +321 + + +510 +2519 +53 @@ -12516,15 +12741,15 @@ using_static_directives -199 +390 id -199 +390 type_id -32 +54 @@ -12538,7 +12763,7 @@ 1 2 -199 +390 @@ -12554,46 +12779,46 @@ 1 2 -4 +2 2 3 -15 +22 3 4 -1 +4 4 5 -3 +5 5 +6 +2 + + +6 7 -2 +5 -7 +8 9 -2 +7 -16 -23 -2 - - -26 -27 -1 - - -30 +12 31 +5 + + +46 +71 2 @@ -12604,15 +12829,15 @@ using_directive_location -74275 +144310 id -74275 +144310 loc -74252 +144267 @@ -12626,7 +12851,7 @@ 1 2 -74275 +144310 @@ -12642,12 +12867,12 @@ 1 2 -74229 +144223 2 3 -22 +43 @@ -12657,11 +12882,11 @@ directive_ifs -2550 +5161 id -2550 +5161 branchTaken @@ -12683,7 +12908,7 @@ 1 2 -2550 +5161 @@ -12699,7 +12924,7 @@ 1 2 -2550 +5161 @@ -12713,13 +12938,13 @@ 12 -1194 -1195 +1992 +1993 1 -1219 -1220 +2162 +2163 1 @@ -12755,13 +12980,13 @@ 12 -1199 -1200 +2013 +2014 1 -1214 -1215 +2141 +2142 1 @@ -12793,15 +13018,15 @@ directive_elifs -7 +59 id -7 +59 branchTaken -1 +2 conditionValue @@ -12809,11 +13034,11 @@ parent -7 +51 index -1 +2 @@ -12827,7 +13052,7 @@ 1 2 -7 +59 @@ -12843,7 +13068,7 @@ 1 2 -7 +59 @@ -12859,7 +13084,7 @@ 1 2 -7 +59 @@ -12875,7 +13100,7 @@ 1 2 -7 +59 @@ -12889,8 +13114,13 @@ 12 -7 -8 +18 +19 +1 + + +41 +42 1 @@ -12905,9 +13135,9 @@ 12 -2 -3 -1 +1 +2 +2 @@ -12921,8 +13151,13 @@ 12 -7 -8 +18 +19 +1 + + +39 +40 1 @@ -12937,9 +13172,9 @@ 12 -1 -2 -1 +2 +3 +2 @@ -12953,13 +13188,13 @@ 12 -1 -2 +18 +19 1 -6 -7 +41 +42 1 @@ -12990,13 +13225,13 @@ 12 -1 -2 +18 +19 1 -6 -7 +39 +40 1 @@ -13011,8 +13246,8 @@ 12 -1 -2 +2 +3 2 @@ -13029,7 +13264,12 @@ 1 2 -7 +43 + + +2 +3 +8 @@ -13045,7 +13285,12 @@ 1 2 -7 +45 + + +2 +3 +6 @@ -13061,7 +13306,12 @@ 1 2 -7 +45 + + +2 +3 +6 @@ -13077,7 +13327,12 @@ 1 2 -7 +43 + + +2 +3 +8 @@ -13091,8 +13346,13 @@ 12 -7 -8 +8 +9 +1 + + +51 +52 1 @@ -13107,9 +13367,9 @@ 12 -1 -2 -1 +2 +3 +2 @@ -13125,7 +13385,7 @@ 2 3 -1 +2 @@ -13139,8 +13399,13 @@ 12 -7 -8 +8 +9 +1 + + +51 +52 1 @@ -13151,11 +13416,11 @@ directive_elses -1140 +2314 id -1140 +2314 branchTaken @@ -13163,11 +13428,11 @@ parent -1140 +2314 index -2 +3 @@ -13181,7 +13446,7 @@ 1 2 -1140 +2314 @@ -13197,7 +13462,7 @@ 1 2 -1140 +2314 @@ -13213,7 +13478,7 @@ 1 2 -1140 +2314 @@ -13227,13 +13492,13 @@ 12 -329 -330 +496 +497 1 -750 -751 +1367 +1368 1 @@ -13248,13 +13513,13 @@ 12 -329 -330 +496 +497 1 -750 -751 +1367 +1368 1 @@ -13271,7 +13536,12 @@ 2 3 -2 +1 + + +3 +4 +1 @@ -13287,7 +13557,7 @@ 1 2 -1140 +2314 @@ -13303,7 +13573,7 @@ 1 2 -1140 +2314 @@ -13319,7 +13589,7 @@ 1 2 -1140 +2314 @@ -13333,13 +13603,18 @@ 12 -7 -8 +1 +2 1 -1072 -1073 +10 +11 +1 + + +1852 +1853 1 @@ -13354,6 +13629,11 @@ 12 +1 +2 +1 + + 2 3 2 @@ -13370,13 +13650,18 @@ 12 -7 -8 +1 +2 1 -1072 -1073 +10 +11 +1 + + +1852 +1853 1 @@ -13387,15 +13672,15 @@ directive_endifs -2550 +5161 id -2550 +5161 start -2550 +5161 @@ -13409,7 +13694,7 @@ 1 2 -2550 +5161 @@ -13425,7 +13710,7 @@ 1 2 -2550 +5161 @@ -13435,15 +13720,15 @@ directive_define_symbols -3314 +6226 id -3314 +6226 name -86 +170 @@ -13457,7 +13742,7 @@ 1 2 -3314 +6226 @@ -13473,52 +13758,52 @@ 1 2 -17 +37 2 3 -8 +27 3 4 -10 +13 4 5 -8 +11 5 -6 -7 - - -6 7 -5 +11 7 -12 -7 +10 +12 -13 -23 -6 +10 +17 +14 -24 -55 -7 +17 +27 +14 -97 -656 -7 +27 +72 +13 + + +77 +1098 +13 @@ -13528,15 +13813,15 @@ directive_regions -565 +1954 id -565 +1954 name -216 +710 @@ -13550,7 +13835,7 @@ 1 2 -565 +1954 @@ -13566,27 +13851,27 @@ 1 2 -6 +8 2 3 -175 +547 3 4 -1 +22 4 5 -26 +81 -6 -31 -8 +5 +35 +52 @@ -13596,15 +13881,15 @@ directive_endregions -565 +1954 id -565 +1954 start -565 +1954 @@ -13618,7 +13903,7 @@ 1 2 -565 +1954 @@ -13634,7 +13919,7 @@ 1 2 -565 +1954 @@ -13644,15 +13929,15 @@ directive_lines -128896 +250436 id -128896 +250436 kind -7 +14 @@ -13666,7 +13951,7 @@ 1 2 -128896 +250436 @@ -13682,12 +13967,12 @@ 16650 16651 -5 +9 18118 18119 -2 +4 @@ -13697,15 +13982,15 @@ directive_line_value -41738 +81095 id -41738 +81095 line -709 +1378 @@ -13719,7 +14004,7 @@ 1 2 -41738 +81095 @@ -13735,57 +14020,57 @@ 1 2 -147 +287 2 3 -70 +136 3 4 -55 +107 4 7 -65 +126 7 11 -60 +116 11 15 -55 +107 15 27 -62 +121 27 46 -55 +107 46 104 -55 +107 106 549 -55 +107 569 727 -27 +53 @@ -13795,15 +14080,15 @@ directive_line_file -41738 +81095 id -41738 +81095 file -2396 +4656 @@ -13817,7 +14102,7 @@ 1 2 -41738 +81095 @@ -13833,57 +14118,57 @@ 1 2 -308 +599 2 3 -396 +769 3 4 -255 +496 4 6 -205 +399 6 7 -110 +214 7 9 -200 +389 9 12 -180 +350 12 16 -205 +399 16 27 -185 +360 27 42 -188 +365 42 2665 -160 +311 @@ -13893,19 +14178,19 @@ directive_nullables -83477 +162190 id -83477 +162190 setting -5 +9 target -2 +4 @@ -13919,7 +14204,7 @@ 1 2 -83477 +162190 @@ -13935,7 +14220,7 @@ 1 2 -83477 +162190 @@ -13951,7 +14236,7 @@ 16650 16651 -5 +9 @@ -13967,7 +14252,7 @@ 1 2 -5 +9 @@ -13983,7 +14268,7 @@ 33300 33301 -2 +4 @@ -13999,7 +14284,7 @@ 2 3 -2 +4 @@ -14057,15 +14342,15 @@ directive_errors -1 +28 id -1 +28 message -1 +2 @@ -14079,7 +14364,7 @@ 1 2 -1 +28 @@ -14093,8 +14378,13 @@ 12 -1 -2 +4 +5 +1 + + +24 +25 1 @@ -14153,15 +14443,15 @@ directive_defines -5 +22 id -5 +22 name -5 +12 @@ -14175,7 +14465,7 @@ 1 2 -5 +22 @@ -14191,7 +14481,22 @@ 1 2 -5 +8 + + +2 +3 +1 + + +3 +4 +1 + + +6 +7 +1 @@ -14201,23 +14506,23 @@ pragma_checksums -2494 +4846 id -2494 +4846 file -2494 +4846 guid -2 +4 bytes -2338 +4544 @@ -14231,7 +14536,7 @@ 1 2 -2494 +4846 @@ -14247,7 +14552,7 @@ 1 2 -2494 +4846 @@ -14263,7 +14568,7 @@ 1 2 -2494 +4846 @@ -14279,7 +14584,7 @@ 1 2 -2494 +4846 @@ -14295,7 +14600,7 @@ 1 2 -2494 +4846 @@ -14311,7 +14616,7 @@ 1 2 -2494 +4846 @@ -14327,7 +14632,7 @@ 995 996 -2 +4 @@ -14343,7 +14648,7 @@ 995 996 -2 +4 @@ -14359,7 +14664,7 @@ 933 934 -2 +4 @@ -14375,12 +14680,12 @@ 1 2 -2288 +4446 2 19 -50 +97 @@ -14396,12 +14701,12 @@ 1 2 -2288 +4446 2 19 -50 +97 @@ -14417,7 +14722,7 @@ 1 2 -2338 +4544 @@ -14427,15 +14732,15 @@ pragma_warnings -14725 +28609 id -14725 +28609 kind -5 +9 @@ -14449,7 +14754,7 @@ 1 2 -14725 +28609 @@ -14465,7 +14770,7 @@ 2937 2938 -5 +9 @@ -14475,19 +14780,19 @@ pragma_warning_error_codes -14730 +28619 id -14725 +28609 errorCode -15 +29 index -5 +9 @@ -14501,12 +14806,12 @@ 1 2 -14720 +28600 2 3 -5 +9 @@ -14522,12 +14827,12 @@ 1 2 -14720 +28600 2 3 -5 +9 @@ -14543,17 +14848,17 @@ 2 3 -5 +9 946 947 -5 +9 1990 1991 -5 +9 @@ -14569,7 +14874,7 @@ 1 2 -15 +29 @@ -14585,12 +14890,12 @@ 2 3 -2 +4 5874 5875 -2 +4 @@ -14606,12 +14911,12 @@ 1 2 -2 +4 5 6 -2 +4 @@ -14621,15 +14926,15 @@ preprocessor_directive_location -229688 +446370 id -229688 +446370 loc -229688 +446370 @@ -14643,7 +14948,7 @@ 1 2 -229688 +446370 @@ -14659,7 +14964,7 @@ 1 2 -229688 +446370 @@ -14669,15 +14974,15 @@ preprocessor_directive_compilation -229688 +446370 id -229688 +446370 compilation -172 +345 @@ -14691,7 +14996,7 @@ 1 2 -229688 +446370 @@ -14707,62 +15012,62 @@ 4 11 -12 +29 16 -62 -15 +48 +29 -75 -144 -15 +61 +140 +29 -149 -226 -15 +143 +198 +29 -248 -317 -15 +225 +300 +29 -342 -459 -15 +316 +453 +29 -503 -665 -15 +458 +634 +29 -772 -1090 -15 +664 +1055 +29 -1155 -1276 -15 +1089 +1250 +29 -1343 -2001 -15 +1275 +1989 +29 -2121 -4115 -15 +2000 +3215 +29 -6086 +4114 19444 -10 +24 @@ -14772,15 +15077,15 @@ preprocessor_directive_active -229688 +446370 id -229688 +446370 active -2 +9 @@ -14794,7 +15099,7 @@ 1 2 -229688 +446370 @@ -14808,9 +15113,14 @@ 12 -91625 -91626 -2 +7 +8 +4 + + +91639 +91640 +4 @@ -14820,19 +15130,19 @@ types -434504 +867165 id -434504 +867165 kind -67 +131 name -184347 +366858 @@ -14846,7 +15156,7 @@ 1 2 -434504 +867165 @@ -14862,7 +15172,7 @@ 1 2 -434504 +867165 @@ -14878,32 +15188,32 @@ 1 2 -42 +82 45 -198 -5 +199 +9 -342 -1750 -5 +366 +1874 +9 -2450 -9903 -5 +2454 +10198 +9 -20838 -35370 -5 +22085 +36570 +9 -40817 -61603 -5 +41596 +62642 +9 @@ -14919,32 +15229,32 @@ 1 2 -42 +82 45 -154 -5 +158 +9 -168 +169 701 -5 +9 -1043 +1086 2228 -5 +9 -6467 -9921 -5 +6598 +10563 +9 -17642 -35459 -5 +18339 +35727 +9 @@ -14960,17 +15270,17 @@ 1 2 -163114 +324610 2 5 -14629 +28838 5 -6327 -6603 +6356 +13408 @@ -14986,12 +15296,12 @@ 1 2 -183613 +365421 2 4 -734 +1436 @@ -15001,15 +15311,15 @@ typerefs -120781 +234791 id -120781 +234791 name -91080 +176982 @@ -15023,7 +15333,7 @@ 1 2 -120781 +234791 @@ -15039,17 +15349,17 @@ 1 2 -83592 +162434 2 7 -6938 +13481 7 2183 -548 +1066 @@ -15059,15 +15369,15 @@ typeref_type -120694 +234611 id -120694 +234611 typeId -120694 +234611 @@ -15081,7 +15391,7 @@ 1 2 -120694 +234611 @@ -15097,7 +15407,7 @@ 1 2 -120694 +234611 @@ -15107,23 +15417,23 @@ array_element_type -4384 +9122 array -4384 +9122 dimension -5 +9 rank -5 +9 element -4379 +9112 @@ -15137,7 +15447,7 @@ 1 2 -4384 +9122 @@ -15153,7 +15463,7 @@ 1 2 -4384 +9122 @@ -15169,7 +15479,7 @@ 1 2 -4384 +9122 @@ -15185,12 +15495,12 @@ 20 21 -2 +4 -1729 -1730 -2 +1853 +1854 +4 @@ -15206,12 +15516,12 @@ 1 2 -2 +4 2 3 -2 +4 @@ -15227,12 +15537,12 @@ 20 21 -2 +4 -1727 -1728 -2 +1851 +1852 +4 @@ -15248,12 +15558,12 @@ 2 3 -2 +4 -1747 -1748 -2 +1871 +1872 +4 @@ -15269,12 +15579,12 @@ 1 2 -2 +4 2 3 -2 +4 @@ -15290,12 +15600,12 @@ 2 3 -2 +4 -1747 -1748 -2 +1871 +1872 +4 @@ -15311,12 +15621,12 @@ 1 2 -4374 +9103 2 3 -5 +9 @@ -15332,7 +15642,7 @@ 1 2 -4379 +9112 @@ -15348,12 +15658,12 @@ 1 2 -4374 +9103 2 3 -5 +9 @@ -15363,15 +15673,15 @@ nullable_underlying_type -550 +979 nullable -550 +979 underlying -550 +979 @@ -15385,7 +15695,7 @@ 1 2 -550 +979 @@ -15401,7 +15711,7 @@ 1 2 -550 +979 @@ -15411,15 +15721,15 @@ pointer_referent_type -112 +219 pointer -112 +219 referent -112 +219 @@ -15433,7 +15743,7 @@ 1 2 -112 +219 @@ -15449,7 +15759,7 @@ 1 2 -112 +219 @@ -15459,15 +15769,15 @@ enum_underlying_type -6141 +11952 enum_id -6141 +11952 underlying_type_id -20 +38 @@ -15481,7 +15791,7 @@ 1 2 -6141 +11952 @@ -15497,37 +15807,37 @@ 5 6 -5 +9 23 24 -2 +4 25 26 -2 +4 41 42 -2 +4 172 173 -2 +4 285 286 -2 +4 -1894 -1895 -2 +1898 +1899 +4 @@ -15537,15 +15847,15 @@ delegate_return_type -52229 +107552 delegate_id -52229 +107552 return_type_id -26697 +55510 @@ -15559,7 +15869,7 @@ 1 2 -52229 +107552 @@ -15575,12 +15885,12 @@ 1 2 -25171 +52198 2 -4000 -1526 +4178 +3312 @@ -15590,15 +15900,15 @@ function_pointer_return_type -9 +11 function_pointer_id -9 +11 return_type_id -6 +3 @@ -15612,7 +15922,7 @@ 1 2 -9 +11 @@ -15626,9 +15936,14 @@ 12 -1 -2 -5 +2 +3 +1 + + +3 +4 +1 4 @@ -15643,15 +15958,15 @@ extend -160600 +323485 sub -160600 +323485 super -16246 +31566 @@ -15665,7 +15980,7 @@ 1 2 -160600 +323485 @@ -15681,27 +15996,27 @@ 1 2 -11646 +22628 2 3 -2050 +3979 3 5 -1240 +2415 5 70 -1223 +2376 70 -20836 -85 +22083 +165 @@ -15711,26 +16026,26 @@ anonymous_types -571 +1212 id -571 +1212 implement -266554 +541624 sub -112586 +226351 super -60780 +122544 @@ -15744,27 +16059,27 @@ 1 2 -51182 +100772 2 3 -27933 +57044 3 4 -17643 +36110 4 7 -9373 +18970 7 21 -6455 +13452 @@ -15780,27 +16095,27 @@ 1 2 -33561 +66951 2 3 -14692 +29783 3 4 -4983 +10247 4 6 -4168 +8694 6 -20685 -3374 +21807 +6867 @@ -15810,15 +16125,15 @@ type_location -277271 +553689 id -237743 +466963 loc -12499 +29876 @@ -15832,17 +16147,17 @@ 1 2 -209975 +407386 2 3 -19400 +39232 3 638 -8367 +20344 @@ -15858,22 +16173,17 @@ 1 2 -10568 +26004 2 -20 -962 +26 +2269 -20 -1759 -937 - - -1782 +26 12195 -30 +1602 @@ -15883,15 +16193,15 @@ tuple_underlying_type -857 +1782 tuple -857 +1782 struct -574 +1139 @@ -15905,7 +16215,7 @@ 1 2 -857 +1782 @@ -15921,17 +16231,17 @@ 1 2 -333 +642 2 3 -213 +423 3 -6 -27 +9 +73 @@ -15941,19 +16251,19 @@ tuple_element -3374 +6789 tuple -854 +1777 index -52 +102 field -3374 +6789 @@ -15967,37 +16277,37 @@ 1 2 -22 +43 2 3 -523 +1134 3 4 -75 +146 4 5 -32 +63 5 7 -72 +141 7 13 -72 +141 13 22 -55 +107 @@ -16013,37 +16323,37 @@ 1 2 -22 +43 2 3 -523 +1134 3 4 -75 +146 4 5 -32 +63 5 7 -72 +141 7 13 -72 +141 13 22 -55 +107 @@ -16059,107 +16369,107 @@ 2 3 -2 +4 4 5 -2 +4 6 7 -2 +4 8 9 -2 +4 10 11 -2 +4 12 13 -2 +4 14 15 -2 +4 18 19 -2 +4 22 23 -2 +4 26 27 -2 +4 30 31 -2 +4 34 35 -2 +4 38 39 -2 +4 43 44 -2 +4 51 52 -2 +4 59 60 -2 +4 80 81 -2 +4 93 94 -2 +4 123 124 -2 +4 -332 -333 -2 +356 +357 +4 -341 -342 -2 +365 +366 +4 @@ -16175,107 +16485,107 @@ 2 3 -2 +4 4 5 -2 +4 6 7 -2 +4 8 9 -2 +4 10 11 -2 +4 12 13 -2 +4 14 15 -2 +4 18 19 -2 +4 22 23 -2 +4 26 27 -2 +4 30 31 -2 +4 34 35 -2 +4 38 39 -2 +4 43 44 -2 +4 51 52 -2 +4 59 60 -2 +4 80 81 -2 +4 93 94 -2 +4 123 124 -2 +4 -332 -333 -2 +356 +357 +4 -341 -342 -2 +365 +366 +4 @@ -16291,7 +16601,7 @@ 1 2 -3374 +6789 @@ -16307,7 +16617,7 @@ 1 2 -3374 +6789 @@ -16317,19 +16627,19 @@ attributes -368399 +745454 id -368399 +745454 type_id -867 +1685 target -219716 +427019 @@ -16343,7 +16653,7 @@ 1 2 -368399 +745454 @@ -16359,7 +16669,7 @@ 1 2 -368399 +745454 @@ -16375,67 +16685,67 @@ 1 2 -115 +189 2 3 -85 +194 3 4 -45 +87 4 7 -72 +141 7 -9 -62 +10 +150 -9 -16 -67 +10 +18 +131 -16 -23 -65 +18 +28 +131 -23 -50 -65 +28 +54 +131 -50 -87 -65 +55 +119 +126 -90 -188 -65 +119 +232 +126 -194 -466 -65 +237 +608 +126 -498 -1735 -65 +616 +4825 +126 -1785 +5142 41857 -27 +19 @@ -16451,62 +16761,62 @@ 1 2 -165 +316 2 3 -67 +131 3 4 -40 +77 4 6 -72 +141 6 9 -72 +141 9 15 -65 +126 15 -26 -67 +25 +126 -26 -48 -65 +25 +47 +131 -48 -82 -67 +47 +81 +126 -82 -182 -65 +81 +176 +126 -183 -607 -65 +180 +563 +126 -607 +596 39377 -52 +112 @@ -16522,17 +16832,17 @@ 1 2 -188082 +365075 2 3 -24348 +47478 3 957 -7284 +14465 @@ -16548,17 +16858,17 @@ 1 2 -202865 +394279 2 16 -16660 +32369 16 20 -190 +370 @@ -16568,15 +16878,15 @@ attribute_location -403061 +813511 id -368399 +745454 loc -36840 +72328 @@ -16590,12 +16900,12 @@ 1 2 -333737 +677397 2 3 -34662 +68056 @@ -16611,12 +16921,12 @@ 1 2 -34677 +68125 4 -22087 -2163 +26599 +4203 @@ -16626,19 +16936,19 @@ type_mention -622003 +1252212 id -622003 +1252212 type_id -21696 +35186 parent -541633 +1030376 @@ -16652,7 +16962,7 @@ 1 2 -622003 +1252212 @@ -16668,7 +16978,7 @@ 1 2 -622003 +1252212 @@ -16684,52 +16994,52 @@ 1 2 -5029 +5682 2 3 -4912 +7203 3 4 -1876 +3551 4 5 -1650 +3839 5 6 -1080 +1995 6 8 -1622 +2856 8 12 -1671 +2927 12 -24 -1673 +22 +2759 -24 -119 -1633 +22 +67 +2652 -119 -44145 -547 +67 +80294 +1717 @@ -16745,47 +17055,52 @@ 1 2 -6457 +9874 2 3 -4662 +5858 3 4 -1635 +3388 4 5 -1239 +2829 5 -7 -1984 +6 +1929 -7 -11 -1965 +6 +8 +2625 -11 -22 -1628 +8 +13 +2874 -22 -120 -1627 +13 +28 +2640 -120 -38647 -494 +28 +207 +2639 + + +207 +66416 +525 @@ -16801,17 +17116,17 @@ 1 2 -480732 +872847 2 3 -55624 +141323 3 187 -5276 +16204 @@ -16827,12 +17142,12 @@ 1 2 -532606 +1011056 2 22 -9026 +19319 @@ -16842,15 +17157,15 @@ type_mention_location -626999 +1252212 id -626999 +1252212 loc -593108 +1163351 @@ -16864,7 +17179,7 @@ 1 2 -626999 +1252212 @@ -16880,12 +17195,12 @@ 1 2 -572155 +1126926 2 -187 -20953 +199 +36425 @@ -16895,15 +17210,15 @@ type_annotation -25557 +50926 id -25557 +50926 annotation -7 +14 @@ -16917,7 +17232,7 @@ 1 2 -25557 +50926 @@ -16931,19 +17246,19 @@ 12 -1305 -1306 -2 +1306 +1307 +4 -2046 -2047 -2 +2047 +2048 +4 -6844 -6845 -2 +7103 +7104 +4 @@ -16953,15 +17268,15 @@ nullability -997 +1996 nullability -997 +1996 kind -7 +14 @@ -16975,7 +17290,7 @@ 1 2 -997 +1996 @@ -16991,17 +17306,17 @@ 13 14 -2 +4 -120 -121 -2 +127 +128 +4 -265 -266 -2 +270 +271 +4 @@ -17011,19 +17326,19 @@ nullability_parent -3146 +6278 nullability -265 +521 index -52 +102 parent -990 +1982 @@ -17037,22 +17352,22 @@ 1 2 -172 +340 2 3 -60 +116 3 5 -17 +34 5 22 -15 +29 @@ -17068,37 +17383,37 @@ 1 2 -125 +243 2 3 -47 +92 3 4 -30 +53 4 5 -15 +38 5 8 -22 +38 8 -41 -20 +44 +43 -136 -201 -5 +138 +207 +9 @@ -17114,37 +17429,37 @@ 1 2 -10 +19 3 4 -27 +53 5 6 -2 +4 7 8 -2 +4 17 18 -5 +9 39 40 -2 +4 -87 -88 -2 +88 +89 +4 @@ -17160,97 +17475,97 @@ 1 2 -5 +9 2 3 -5 +9 4 5 -2 +4 6 7 -2 +4 8 9 -2 +4 10 11 -2 +4 12 13 -2 +4 14 15 -2 +4 16 17 -2 +4 20 21 -2 +4 22 23 -2 +4 40 41 -2 +4 44 45 -2 +4 -51 -52 -2 +52 +53 +4 -67 -68 -2 +69 +70 +4 -94 -95 -2 +97 +98 +4 -151 -152 -2 +157 +158 +4 -295 -296 -2 +305 +306 +4 -395 -396 -2 +407 +408 +4 @@ -17266,17 +17581,17 @@ 1 2 -295 +594 2 3 -616 +1227 3 4 -77 +160 @@ -17292,37 +17607,37 @@ 1 2 -250 +496 2 3 -360 +720 3 4 -142 +292 4 5 -67 +136 5 8 -67 +141 8 -14 -75 +15 +155 -14 +15 22 -25 +38 @@ -17332,15 +17647,15 @@ type_nullability -2271603 +4596996 id -2238788 +4529942 nullability -601 +959 @@ -17354,12 +17669,12 @@ 1 2 -2209099 +4469255 2 9 -29689 +60687 @@ -17375,57 +17690,62 @@ 1 2 -131 +163 2 3 -81 +146 3 4 -35 +60 4 5 -38 +67 5 7 -48 +81 7 10 -48 +66 10 -13 -46 +14 +73 -13 +14 23 -50 +77 23 -61 -46 +41 +72 -63 -224 -46 +41 +123 +72 -278 -1814893 -32 +123 +4117 +72 + + +4580 +3677458 +10 @@ -17435,11 +17755,11 @@ expr_flowstate -1300115 +2970146 id -1300115 +2970146 state @@ -17457,7 +17777,7 @@ 1 2 -1300115 +2970146 @@ -17471,13 +17791,13 @@ 12 -116006 -116007 +197316 +197317 1 -1113915 -1113916 +2192983 +2192984 1 @@ -17488,23 +17808,23 @@ type_parameters -102354 +202684 id -102354 +202684 index -52 +102 generic_id -51560 +103704 variance -7 +14 @@ -17518,7 +17838,7 @@ 1 2 -102354 +202684 @@ -17534,7 +17854,7 @@ 1 2 -102354 +202684 @@ -17550,7 +17870,7 @@ 1 2 -102354 +202684 @@ -17566,107 +17886,107 @@ 5 6 -2 +4 8 9 -2 +4 12 13 -2 +4 15 16 -2 +4 48 49 -2 +4 170 171 -2 +4 298 299 -2 +4 429 430 -2 +4 560 561 -2 +4 691 692 -2 +4 822 823 -2 +4 954 955 -2 +4 1089 1090 -2 +4 1240 1241 -2 +4 1385 1386 -2 +4 1539 1540 -2 +4 -1753 -1754 -2 +1757 +1758 +4 -2007 -2008 -2 +2015 +2016 +4 -2524 -2525 -2 +2536 +2537 +4 -4710 -4711 -2 +4744 +4745 +4 -20558 -20559 -2 +21279 +21280 +4 @@ -17682,107 +18002,107 @@ 5 6 -2 +4 8 9 -2 +4 12 13 -2 +4 15 16 -2 +4 48 49 -2 +4 170 171 -2 +4 298 299 -2 +4 429 430 -2 +4 560 561 -2 +4 691 692 -2 +4 822 823 -2 +4 954 955 -2 +4 1089 1090 -2 +4 1240 1241 -2 +4 1385 1386 -2 +4 1539 1540 -2 +4 -1753 -1754 -2 +1757 +1758 +4 -2007 -2008 -2 +2015 +2016 +4 -2524 -2525 -2 +2536 +2537 +4 -4712 -4713 -2 +4748 +4749 +4 -20568 -20569 -2 +21292 +21293 +4 @@ -17798,17 +18118,17 @@ 1 2 -10 +19 2 3 -2 +4 3 4 -40 +77 @@ -17824,22 +18144,22 @@ 1 2 -39748 +80579 2 3 -5484 +10773 3 -10 -3935 +11 +8348 -10 +11 22 -2391 +4003 @@ -17855,22 +18175,22 @@ 1 2 -39748 +80579 2 3 -5484 +10773 3 -10 -3935 +11 +8348 -10 +11 22 -2391 +4003 @@ -17886,12 +18206,12 @@ 1 2 -51482 +103553 2 3 -77 +150 @@ -17907,17 +18227,17 @@ 68 69 -2 +4 310 311 -2 +4 -40440 -40441 -2 +41219 +41220 +4 @@ -17933,17 +18253,17 @@ 16 17 -2 +4 17 18 -2 +4 21 22 -2 +4 @@ -17959,17 +18279,17 @@ 65 66 -2 +4 72 73 -2 +4 -20462 -20463 -2 +21186 +21187 +4 @@ -17979,19 +18299,19 @@ type_arguments -315219 +643766 id -136875 +273250 index -52 +102 constructed_id -201248 +412875 @@ -18005,17 +18325,17 @@ 1 2 -119004 +234660 2 3 -17166 +37113 3 21 -704 +1475 @@ -18031,27 +18351,27 @@ 1 2 -88393 +173928 2 3 -27419 +56469 3 5 -10305 +20568 5 -25 -10278 +23 +20651 -25 -2394 -478 +23 +2800 +1631 @@ -18067,97 +18387,97 @@ 2 3 -7 +14 3 4 -2 +4 55 56 -2 +4 167 168 -2 +4 283 284 -2 +4 402 403 -2 +4 521 522 -2 +4 640 641 -2 +4 759 760 -2 +4 883 884 -2 +4 1002 1003 -2 +4 1232 1233 -2 +4 1327 1328 -2 +4 -1510 -1511 -2 +1515 +1516 +4 -1717 -1718 -2 +1729 +1730 +4 -1979 -1980 -2 +2010 +2011 +4 -3839 -3840 -2 +4190 +4191 +4 -13565 -13566 -2 +14311 +14312 +4 -32507 -32508 -2 +33697 +33698 +4 @@ -18173,97 +18493,97 @@ 2 3 -5 +9 3 4 -5 +9 96 97 -2 +4 227 228 -2 +4 365 366 -2 +4 503 504 -2 +4 641 642 -2 +4 779 780 -2 +4 917 918 -2 +4 1061 1062 -2 +4 1201 1202 -2 +4 1456 1457 -2 +4 -1641 -1642 -2 +1643 +1644 +4 -1859 -1860 -2 +1866 +1867 +4 -2240 -2241 -2 +2254 +2255 +4 -2987 -2988 -2 +3022 +3023 +4 -5285 -5286 -2 +5701 +5702 +4 -24196 -24197 -2 +25663 +25664 +4 -80280 -80281 -2 +84769 +84770 +4 @@ -18279,17 +18599,17 @@ 1 2 -141661 +290043 2 3 -46887 +96228 3 22 -12699 +26603 @@ -18305,17 +18625,17 @@ 1 2 -140593 +287881 2 3 -47406 +97226 3 22 -13248 +27767 @@ -18325,15 +18645,15 @@ constructed_generic -201248 +412875 constructed -201248 +412875 generic -4256 +8577 @@ -18347,7 +18667,7 @@ 1 2 -201248 +412875 @@ -18363,47 +18683,47 @@ 1 2 -1737 +3443 2 3 -551 +1154 3 4 -293 +618 4 6 -330 +652 6 11 -350 +725 11 -25 -328 +26 +647 -25 -61 -320 +26 +63 +657 -61 -2054 -320 +63 +2866 +647 -2323 -10856 -22 +2964 +11327 +29 @@ -18413,15 +18733,15 @@ type_parameter_constraints -273733 +594129 id -273733 +594129 param_id -102321 +202597 @@ -18435,7 +18755,7 @@ 1 2 -273733 +594129 @@ -18451,17 +18771,22 @@ 1 2 -86049 +167246 2 3 -9393 +19984 3 -1740 -6878 +307 +15196 + + +311 +2109 +170 @@ -18507,11 +18832,11 @@ general_type_parameter_constraints -40912 +106692 id -23697 +60453 kind @@ -18529,12 +18854,12 @@ 1 2 -6482 +14214 2 3 -17215 +46239 @@ -18553,23 +18878,23 @@ 1 -172 -173 +279 +280 1 -2708 -2709 +5837 +5838 1 -17170 -17171 +46182 +46183 1 -20858 -20859 +54390 +54391 1 @@ -18580,15 +18905,15 @@ specific_type_parameter_constraints -20140 +46370 id -19736 +45666 base_id -787 +1286 @@ -18602,12 +18927,12 @@ 1 2 -19370 +45008 2 5 -366 +658 @@ -18628,48 +18953,58 @@ 2 3 -181 +260 3 4 -57 +70 4 5 -87 +92 5 +6 +57 + + +6 7 -70 +138 7 10 -53 +108 10 15 -63 +99 15 -26 +21 +111 + + +21 +37 +97 + + +37 +106 +97 + + +108 +4902 60 - -26 -55 -61 - - -56 -3216 -58 - @@ -18678,19 +19013,19 @@ specific_type_parameter_nullability -13207 +31518 id -13161 +31372 base_id -506 +912 nullability -11 +17 @@ -18704,12 +19039,12 @@ 1 2 -13115 +31226 2 3 -46 +146 @@ -18725,7 +19060,7 @@ 1 2 -13161 +31372 @@ -18741,57 +19076,62 @@ 1 2 -99 +97 2 3 -107 +154 3 4 -37 +45 4 5 -31 +42 5 6 -16 +51 6 7 -41 +102 7 -10 -32 +9 +73 -10 +9 13 -39 +84 -13 -26 -38 +14 +20 +65 -26 -82 -40 +20 +28 +69 -84 -2385 -26 +28 +76 +73 + + +77 +4327 +57 @@ -18807,12 +19147,12 @@ 1 2 -497 +890 2 3 -9 +22 @@ -18833,17 +19173,37 @@ 4 5 -2 +1 6 7 -1 +3 8 9 -2 +1 + + +10 +11 +1 + + +12 +13 +1 + + +16 +17 +1 + + +18 +19 +1 24 @@ -18851,18 +19211,28 @@ 1 -41 -42 +64 +65 1 -132 -133 +72 +73 1 -12930 -12931 +117 +118 +1 + + +386 +387 +1 + + +30619 +30620 1 @@ -18879,12 +19249,12 @@ 1 2 -2 +6 2 3 -4 +3 3 @@ -18894,21 +19264,26 @@ 5 6 -1 - - -6 -7 -1 +2 9 10 +2 + + +12 +13 1 -482 -483 +43 +44 +1 + + +836 +837 1 @@ -18919,15 +19294,15 @@ function_pointer_calling_conventions -9 +11 id -9 +11 kind -2 +1 @@ -18941,7 +19316,7 @@ 1 2 -9 +11 @@ -18955,13 +19330,8 @@ 12 -1 -2 -1 - - -8 -9 +9 +10 1 @@ -19052,15 +19422,15 @@ modifiers -42 +82 id -42 +82 name -42 +82 @@ -19074,7 +19444,7 @@ 1 2 -42 +82 @@ -19090,7 +19460,7 @@ 1 2 -42 +82 @@ -19100,15 +19470,15 @@ has_modifiers -2748133 +5504557 id -1841097 +3697015 mod_id -40 +82 @@ -19122,17 +19492,17 @@ 1 2 -1002460 +2024955 2 3 -771185 +1538421 3 5 -67451 +133639 @@ -19146,84 +19516,89 @@ 12 -5 -6 -2 +1 +2 +4 + + +15 +16 +4 28 29 -2 +4 -149 -150 -2 +151 +152 +4 360 361 -2 +4 -5658 -5659 -2 +6163 +6164 +4 -16373 -16374 -2 +16387 +16388 +4 -22977 -22978 -2 +23884 +23885 +4 -29954 -29955 -2 +30035 +30036 +4 -30538 -30539 -2 +30651 +30652 +4 -37974 -37975 -2 +38027 +38028 +4 -60421 -60422 -2 +62139 +62140 +4 -63249 -63250 -2 +63916 +63917 +4 -68508 -68509 -2 +68706 +68707 +4 -78672 -78673 -2 +83872 +83873 +4 -89979 -89980 -2 +96025 +96026 +4 -591411 -591412 -2 +609801 +609802 +4 @@ -19233,26 +19608,26 @@ compiler_generated -64039 +136181 id -64039 +136181 exprorstmt_name -1469 +3751 parent_id -1469 +3751 name -118 +374 @@ -19266,7 +19641,7 @@ 1 2 -1469 +3751 @@ -19282,47 +19657,47 @@ 2 3 -43 +110 3 4 -9 +55 4 5 -12 +50 5 -7 -10 +6 +34 -7 -9 -9 +6 +8 +32 -10 -15 -9 +8 +12 +28 -16 -26 -7 +12 +23 +31 -26 -52 -10 +25 +214 +28 -54 -131 -5 +239 +240 +1 @@ -19332,19 +19707,19 @@ nested_types -57075 +111931 id -57075 +111931 declaring_type_id -20621 +40596 unbound_id -41748 +81114 @@ -19358,7 +19733,7 @@ 1 2 -57075 +111931 @@ -19374,7 +19749,7 @@ 1 2 -57075 +111931 @@ -19390,32 +19765,32 @@ 1 2 -11922 +23486 2 3 -3253 +6336 3 4 -1566 +3229 4 7 -1732 +3355 7 12 -1581 +3092 12 262 -564 +1095 @@ -19431,32 +19806,32 @@ 1 2 -11940 +23520 2 3 -3296 +6419 3 4 -1524 +3146 4 7 -1742 +3385 7 12 -1579 +3078 12 206 -538 +1047 @@ -19472,12 +19847,12 @@ 1 2 -40237 +78100 2 415 -1511 +3014 @@ -19493,12 +19868,12 @@ 1 2 -40613 +78840 2 415 -1135 +2274 @@ -19508,27 +19883,27 @@ properties -212542 +425592 id -212542 +425592 name -43400 +84358 declaring_type_id -58256 +117951 type_id -26015 +53011 unbound_id -171648 +333840 @@ -19542,7 +19917,7 @@ 1 2 -212542 +425592 @@ -19558,7 +19933,7 @@ 1 2 -212542 +425592 @@ -19574,7 +19949,7 @@ 1 2 -212542 +425592 @@ -19590,7 +19965,7 @@ 1 2 -212542 +425592 @@ -19606,32 +19981,32 @@ 1 2 -26111 +50751 2 3 -7204 +13993 3 4 -2970 +5752 4 7 -3414 +6648 7 -50 -3276 +49 +6336 -50 -2493 -423 +49 +2886 +876 @@ -19647,32 +20022,32 @@ 1 2 -26111 +50751 2 3 -7239 +14061 3 4 -2963 +5737 4 7 -3431 +6682 7 -52 -3256 +51 +6331 -52 -2224 -398 +51 +2578 +793 @@ -19688,17 +20063,17 @@ 1 2 -37474 +72834 2 3 -3569 +6930 3 -522 -2356 +773 +4592 @@ -19714,32 +20089,32 @@ 1 2 -26331 +51180 2 3 -7340 +14256 3 4 -2963 +5737 4 7 -3304 +6443 7 -70 -3256 +68 +6326 -70 +68 2018 -205 +414 @@ -19755,42 +20130,42 @@ 1 2 -19786 +40635 2 3 -14574 +30139 3 4 -5590 +10900 4 5 -4013 +7841 5 6 -3629 +7184 6 8 -4670 +9327 8 -15 -4396 +16 +9565 -15 +16 250 -1594 +2357 @@ -19806,42 +20181,42 @@ 1 2 -22107 +45418 2 3 -12293 +25434 3 4 -5587 +10895 4 5 -4023 +7914 5 6 -3637 +7145 6 8 -4647 +9283 8 15 -4605 +9224 15 250 -1353 +2634 @@ -19857,32 +20232,32 @@ 1 2 -22884 +46699 2 3 -15963 +32886 3 4 -6963 +13890 4 5 -3873 +7544 5 7 -4828 +9380 7 48 -3742 +7549 @@ -19898,42 +20273,42 @@ 1 2 -19786 +40635 2 3 -14574 +30139 3 4 -5590 +10900 4 5 -4013 +7841 5 6 -3629 +7184 6 8 -4670 +9327 8 -15 -4396 +16 +9565 -15 +16 250 -1594 +2357 @@ -19949,27 +20324,27 @@ 1 2 -15635 +32014 2 3 -5319 +10953 3 5 -2353 +4700 5 -19 -1955 +21 +3984 -19 -11856 -752 +21 +12516 +1358 @@ -19985,17 +20360,17 @@ 1 2 -21932 +44809 2 3 -2213 +4461 3 3289 -1870 +3740 @@ -20011,27 +20386,27 @@ 1 2 -16244 +33193 2 3 -5169 +10666 3 5 -2243 +4490 5 -30 -1952 +35 +3993 -30 -5894 -406 +35 +6176 +667 @@ -20047,27 +20422,27 @@ 1 2 -15707 +32155 2 3 -5392 +11080 3 5 -2356 +4739 5 -21 -1975 +23 +4003 -21 -10599 -584 +23 +10636 +1032 @@ -20083,12 +20458,12 @@ 1 2 -169043 +328609 2 -585 -2604 +705 +5231 @@ -20104,7 +20479,7 @@ 1 2 -171648 +333840 @@ -20120,12 +20495,12 @@ 1 2 -169043 +328609 2 -585 -2604 +705 +5231 @@ -20141,12 +20516,12 @@ 1 2 -171048 +332608 2 -438 -599 +690 +1232 @@ -20156,15 +20531,15 @@ property_location -263937 +536505 id -212542 +425592 loc -24308 +52894 @@ -20178,17 +20553,17 @@ 1 2 -171527 +340167 2 3 -32779 +64106 3 119 -8234 +21318 @@ -20204,12 +20579,12 @@ 1 2 -22594 +49412 2 7080 -1714 +3482 @@ -20219,27 +20594,27 @@ indexers -7590 +17042 id -7590 +17042 name -10 +19 declaring_type_id -6071 +13549 type_id -1817 +3969 unbound_id -2283 +4437 @@ -20253,7 +20628,7 @@ 1 2 -7590 +17042 @@ -20269,7 +20644,7 @@ 1 2 -7590 +17042 @@ -20285,7 +20660,7 @@ 1 2 -7590 +17042 @@ -20301,7 +20676,7 @@ 1 2 -7590 +17042 @@ -20317,22 +20692,22 @@ 2 3 -2 +4 3 4 -2 +4 6 7 -2 +4 -3017 -3018 -2 +3488 +3489 +4 @@ -20348,22 +20723,22 @@ 2 3 -2 +4 3 4 -2 +4 4 5 -2 +4 -2415 -2416 -2 +2775 +2776 +4 @@ -20379,17 +20754,17 @@ 1 2 -5 +9 4 5 -2 +4 -720 -721 -2 +810 +811 +4 @@ -20405,22 +20780,22 @@ 2 3 -2 +4 3 4 -2 +4 6 7 -2 +4 900 901 -2 +4 @@ -20436,17 +20811,17 @@ 1 2 -4770 +10505 2 3 -1160 +2747 3 7 -140 +297 @@ -20462,12 +20837,12 @@ 1 2 -6066 +13540 2 3 -5 +9 @@ -20483,12 +20858,12 @@ 1 2 -5046 +11046 2 3 -1025 +2503 @@ -20504,17 +20879,17 @@ 1 2 -4770 +10505 2 3 -1160 +2747 3 7 -140 +297 @@ -20530,27 +20905,32 @@ 1 2 -461 +876 2 3 -423 +871 3 4 -674 +1626 4 6 -120 +267 6 -886 -137 +18 +301 + + +18 +1020 +24 @@ -20566,12 +20946,12 @@ 1 2 -1814 +3964 2 3 -2 +4 @@ -20587,27 +20967,27 @@ 1 2 -541 +1032 2 3 -376 +779 3 4 -691 +1660 4 -7 -165 +6 +238 -7 -845 -42 +6 +978 +258 @@ -20623,27 +21003,27 @@ 1 2 -461 +876 2 3 -423 +871 3 4 -686 +1651 4 6 -120 +267 6 198 -125 +301 @@ -20659,12 +21039,12 @@ 1 2 -2118 +4101 2 -384 -165 +452 +336 @@ -20680,7 +21060,7 @@ 1 2 -2283 +4437 @@ -20696,12 +21076,12 @@ 1 2 -2118 +4101 2 -384 -165 +452 +336 @@ -20717,12 +21097,12 @@ 1 2 -2190 +4247 2 -384 -92 +452 +189 @@ -20732,15 +21112,15 @@ indexer_location -12780 +23899 id -6439 +12715 loc -183 +221 @@ -20754,27 +21134,27 @@ 1 2 -2232 +4500 2 3 -3081 +6699 3 4 -283 +285 4 5 -774 +1117 5 -11 -69 +13 +114 @@ -20790,52 +21170,52 @@ 1 2 -49 +76 2 3 -20 +24 3 4 -19 +17 4 5 -14 +13 5 8 -14 +18 8 13 -14 +17 13 -20 -14 +21 +18 -20 -35 -14 +23 +45 +18 -36 -112 -14 +47 +2319 +17 -124 -2196 -11 +3540 +5342 +3 @@ -20845,27 +21225,27 @@ accessors -284483 +569927 id -284483 +569927 kind -5 +9 name -62337 +121243 declaring_member_id -220132 +442634 unbound_id -226384 +440418 @@ -20879,7 +21259,7 @@ 1 2 -284483 +569927 @@ -20895,7 +21275,7 @@ 1 2 -284483 +569927 @@ -20911,7 +21291,7 @@ 1 2 -284483 +569927 @@ -20927,7 +21307,7 @@ 1 2 -284483 +569927 @@ -20941,14 +21321,14 @@ 12 -25718 -25719 -2 +26183 +26184 +4 -87765 -87766 -2 +90831 +90832 +4 @@ -20962,14 +21342,14 @@ 12 -6501 -6502 -2 +6520 +6521 +4 -18366 -18367 -2 +18373 +18374 +4 @@ -20983,14 +21363,14 @@ 12 -25717 -25718 -2 +26182 +26183 +4 -87764 -87765 -2 +90830 +90831 +4 @@ -21004,14 +21384,14 @@ 12 -20971 -20972 -2 +21018 +21019 +4 -69336 -69337 -2 +69406 +69407 +4 @@ -21027,27 +21407,27 @@ 1 2 -38650 +75192 2 3 -10267 +19949 3 4 -4103 +7929 4 8 -5186 +10111 8 -2204 -4128 +2558 +8060 @@ -21063,7 +21443,7 @@ 1 2 -62337 +121243 @@ -21079,27 +21459,27 @@ 1 2 -38655 +75201 2 3 -10262 +19940 3 4 -4103 +7929 4 8 -5186 +10111 8 -2204 -4128 +2558 +8060 @@ -21115,27 +21495,27 @@ 1 2 -38981 +75840 2 3 -10611 +20617 3 4 -4020 +7763 4 8 -4933 +9653 8 1202 -3790 +7369 @@ -21151,17 +21531,17 @@ 1 2 -155787 +315351 2 3 -64342 +127278 4 5 -2 +4 @@ -21177,12 +21557,12 @@ 1 2 -155787 +315351 2 3 -64345 +127283 @@ -21198,12 +21578,12 @@ 1 2 -155787 +315351 2 3 -64345 +127283 @@ -21219,17 +21599,17 @@ 1 2 -155787 +315351 2 3 -64342 +127278 4 5 -2 +4 @@ -21245,12 +21625,12 @@ 1 2 -223033 +433697 2 -585 -3351 +705 +6721 @@ -21266,7 +21646,7 @@ 1 2 -226384 +440418 @@ -21282,7 +21662,7 @@ 1 2 -226384 +440418 @@ -21298,12 +21678,12 @@ 1 2 -223033 +433697 2 -585 -3351 +705 +6721 @@ -21324,15 +21704,15 @@ accessor_location -367482 +749823 id -284483 +569927 loc -43067 +93213 @@ -21346,17 +21726,17 @@ 1 2 -219889 +434768 2 3 -50297 +98405 3 119 -14296 +36753 @@ -21372,12 +21752,12 @@ 1 2 -41305 +89609 2 -7862 -1762 +8548 +3604 @@ -21387,27 +21767,27 @@ events -7838 +15230 id -7838 +15230 name -6685 +12989 declaring_type_id -631 +1227 type_id -3276 +6365 unbound_id -7833 +15220 @@ -21421,7 +21801,7 @@ 1 2 -7838 +15230 @@ -21437,7 +21817,7 @@ 1 2 -7838 +15230 @@ -21453,7 +21833,7 @@ 1 2 -7838 +15230 @@ -21469,7 +21849,7 @@ 1 2 -7838 +15230 @@ -21485,17 +21865,17 @@ 1 2 -6176 +12001 2 12 -503 +978 14 17 -5 +9 @@ -21511,17 +21891,17 @@ 1 2 -6176 +12001 2 10 -503 +978 14 17 -5 +9 @@ -21537,12 +21917,12 @@ 1 2 -6613 +12848 2 10 -72 +141 @@ -21558,17 +21938,17 @@ 1 2 -6176 +12001 2 12 -503 +978 14 17 -5 +9 @@ -21584,32 +21964,32 @@ 1 2 -318 +618 2 3 -117 +228 3 4 -50 +97 4 8 -55 +107 8 23 -52 +102 58 465 -37 +73 @@ -21625,32 +22005,32 @@ 1 2 -318 +618 2 3 -122 +238 3 4 -47 +92 4 8 -52 +102 8 23 -52 +102 58 465 -37 +73 @@ -21666,27 +22046,27 @@ 1 2 -396 +769 2 3 -102 +199 3 5 -45 +87 5 11 -47 +92 12 181 -40 +77 @@ -21702,32 +22082,32 @@ 1 2 -318 +618 2 3 -117 +228 3 4 -50 +97 4 8 -55 +107 8 23 -52 +102 58 465 -37 +73 @@ -21743,22 +22123,22 @@ 1 2 -2271 +4412 2 3 -599 +1164 3 6 -265 +516 6 318 -140 +272 @@ -21774,22 +22154,22 @@ 1 2 -2471 +4802 2 3 -471 +915 3 8 -258 +501 8 242 -75 +146 @@ -21805,17 +22185,17 @@ 1 2 -2960 +5752 2 4 -268 +521 4 27 -47 +92 @@ -21831,22 +22211,22 @@ 1 2 -2271 +4412 2 3 -599 +1164 3 6 -265 +516 6 318 -140 +272 @@ -21862,12 +22242,12 @@ 1 2 -7828 +15210 2 3 -5 +9 @@ -21883,7 +22263,7 @@ 1 2 -7833 +15220 @@ -21899,12 +22279,12 @@ 1 2 -7828 +15210 2 3 -5 +9 @@ -21920,12 +22300,12 @@ 1 2 -7828 +15210 2 3 -5 +9 @@ -21935,15 +22315,15 @@ event_location -8167 +15868 id -7838 +15230 loc -167 +326 @@ -21957,12 +22337,12 @@ 1 2 -7510 +14592 2 3 -328 +638 @@ -21978,57 +22358,57 @@ 1 2 -25 +48 2 3 -25 +48 3 4 -22 +43 4 5 -12 +24 5 6 -7 +14 6 8 -12 +24 8 9 -10 +19 10 11 -10 +19 12 16 -15 +29 16 31 -15 +29 64 2199 -12 +24 @@ -22038,27 +22418,27 @@ event_accessors -15677 +30460 id -15677 +30460 kind -5 +9 name -13737 +26690 declaring_event_id -7838 +15230 unbound_id -15667 +30441 @@ -22072,7 +22452,7 @@ 1 2 -15677 +30460 @@ -22088,7 +22468,7 @@ 1 2 -15677 +30460 @@ -22104,7 +22484,7 @@ 1 2 -15677 +30460 @@ -22120,7 +22500,7 @@ 1 2 -15677 +30460 @@ -22136,7 +22516,7 @@ 3127 3128 -5 +9 @@ -22152,7 +22532,7 @@ 2740 2741 -5 +9 @@ -22168,7 +22548,7 @@ 3127 3128 -5 +9 @@ -22184,7 +22564,7 @@ 3125 3126 -5 +9 @@ -22200,12 +22580,12 @@ 1 2 -12714 +24703 2 16 -1022 +1987 @@ -22221,7 +22601,7 @@ 1 2 -13737 +26690 @@ -22237,12 +22617,12 @@ 1 2 -12714 +24703 2 16 -1022 +1987 @@ -22258,12 +22638,12 @@ 1 2 -12714 +24703 2 16 -1022 +1987 @@ -22279,7 +22659,7 @@ 2 3 -7838 +15230 @@ -22295,7 +22675,7 @@ 2 3 -7838 +15230 @@ -22311,7 +22691,7 @@ 2 3 -7838 +15230 @@ -22327,7 +22707,7 @@ 2 3 -7838 +15230 @@ -22343,12 +22723,12 @@ 1 2 -15657 +30421 2 3 -10 +19 @@ -22364,7 +22744,7 @@ 1 2 -15667 +30441 @@ -22380,7 +22760,7 @@ 1 2 -15667 +30441 @@ -22396,12 +22776,12 @@ 1 2 -15657 +30421 2 3 -10 +19 @@ -22411,15 +22791,15 @@ event_accessor_location -16334 +31736 id -15677 +30460 loc -167 +326 @@ -22433,12 +22813,12 @@ 1 2 -15020 +29184 2 3 -656 +1276 @@ -22454,57 +22834,57 @@ 2 3 -25 +48 4 5 -25 +48 6 7 -22 +43 8 9 -12 +24 10 11 -7 +14 12 15 -12 +24 16 17 -10 +19 20 21 -10 +19 24 31 -15 +29 32 61 -15 +29 128 4397 -12 +24 @@ -22514,31 +22894,31 @@ operators -6201 +12410 id -6201 +12410 name -65 +126 symbol -60 +116 declaring_type_id -1448 +3024 type_id -809 +1621 unbound_id -5903 +11655 @@ -22552,7 +22932,7 @@ 1 2 -6201 +12410 @@ -22568,7 +22948,7 @@ 1 2 -6201 +12410 @@ -22584,7 +22964,7 @@ 1 2 -6201 +12410 @@ -22600,7 +22980,7 @@ 1 2 -6201 +12410 @@ -22616,7 +22996,7 @@ 1 2 -6201 +12410 @@ -22632,375 +23012,80 @@ 1 2 -2 +4 2 3 -10 +19 3 -4 -5 +5 +9 5 6 -2 +4 8 9 -7 +9 -10 -17 -5 +9 +11 +9 -26 -46 -5 - - -54 -55 -5 - - -57 -58 -5 - - -65 -73 -5 - - -80 -436 -5 - - -454 -500 -5 - - -506 -507 -2 - - - - - - -name -symbol - - -12 - - -1 -2 -65 - - - - - - -name -declaring_type_id - - -12 - - -1 -2 -2 - - -2 -3 -10 - - -3 -4 -5 - - -5 -6 -2 - - -8 -9 -7 - - -10 -15 -5 - - -26 -32 -5 - - -36 -50 -5 - - -50 -52 -5 - - -52 -53 -5 - - -63 -120 -5 - - -201 -444 -5 - - -451 -452 -2 - - - - - - -name -type_id - - -12 - - -1 -2 -7 - - -2 -3 -20 - - -3 -4 -5 - - -5 -6 -2 - - -8 -9 -7 - - -10 -15 -5 - - -26 -32 -5 - - -37 -52 -5 - - -63 -155 -5 - - -181 -182 -2 - - - - - - -name -unbound_id - - -12 - - -1 -2 -2 - - -2 -3 -10 - - -3 -4 -5 - - -5 -6 -2 - - -8 -9 -7 - - -10 -17 -5 - - -26 -46 -5 - - -53 -54 -5 - - -56 -57 -5 - - -65 -73 -5 - - -80 -415 -5 - - -416 -472 -5 - - -478 -479 -2 - - - - - - -symbol -id - - -12 - - -1 -2 -2 - - -2 -3 -10 - - -3 -4 -5 - - -8 -9 -7 - - -10 -17 -5 +17 +27 +9 45 46 -2 +4 54 55 -5 +9 57 58 -5 +9 -72 -86 -5 +66 +74 +9 -91 -436 -5 +85 +437 +9 -454 -500 -5 +459 +532 +9 -506 -507 -2 +532 +533 +4 -symbol -name +name +symbol 12 @@ -23008,19 +23093,14 @@ 1 2 -55 - - -2 -3 -5 +126 -symbol +name declaring_type_id @@ -23029,113 +23109,428 @@ 1 2 -2 +4 2 3 -10 +19 3 -4 -5 +5 +9 + + +5 +6 +4 8 9 -7 +9 -10 -15 -5 +9 +11 +9 -31 -37 -5 - - -49 -51 -5 - - -51 -52 -2 - - -52 -53 -5 - - -63 -120 -5 - - -201 -444 -5 - - -451 -452 -2 - - - - - - -symbol -type_id - - -12 - - -1 -2 -7 - - -2 -3 -20 - - -3 -4 -5 - - -8 -9 -7 - - -10 -15 -5 +15 +27 +9 31 38 -5 +9 -51 -64 -5 +49 +51 +9 -154 -182 -5 +52 +53 +14 + + +68 +121 +9 + + +206 +476 +9 + + +477 +478 +4 + + + + + + +name +type_id + + +12 + + +1 +2 +14 + + +2 +3 +38 + + +3 +5 +9 + + +5 +6 +4 + + +8 +9 +9 + + +9 +11 +9 + + +15 +27 +9 + + +31 +39 +9 + + +52 +69 +9 + + +155 +186 +9 + + + + + + +name +unbound_id + + +12 + + +1 +2 +4 + + +2 +3 +19 + + +3 +5 +9 + + +5 +6 +4 + + +8 +9 +9 + + +9 +11 +9 + + +17 +27 +9 + + +45 +46 +4 + + +53 +54 +9 + + +56 +57 +9 + + +66 +74 +9 + + +85 +415 +9 + + +416 +489 +9 + + +489 +490 +4 + + + + + + +symbol +id + + +12 + + +1 +2 +4 + + +2 +3 +19 + + +3 +5 +9 + + +8 +9 +9 + + +9 +11 +9 + + +17 +46 +9 + + +54 +55 +9 + + +57 +58 +9 + + +73 +91 +9 + + +92 +437 +9 + + +459 +532 +9 + + +532 +533 +4 + + + + + + +symbol +name + + +12 + + +1 +2 +107 + + +2 +3 +9 + + + + + + +symbol +declaring_type_id + + +12 + + +1 +2 +4 + + +2 +3 +19 + + +3 +5 +9 + + +8 +9 +9 + + +9 +11 +9 + + +15 +32 +9 + + +37 +50 +9 + + +50 +51 +4 + + +52 +53 +14 + + +68 +121 +9 + + +206 +476 +9 + + +477 +478 +4 + + + + + + +symbol +type_id + + +12 + + +1 +2 +14 + + +2 +3 +38 + + +3 +5 +9 + + +8 +9 +9 + + +9 +11 +9 + + +15 +32 +9 + + +38 +53 +9 + + +68 +156 +9 + + +185 +186 +4 @@ -23151,62 +23546,62 @@ 1 2 -2 +4 2 3 -10 +19 3 -4 -5 +5 +9 8 9 -7 +9 -10 -17 -5 +9 +11 +9 -45 +17 46 -2 +9 53 54 -5 +9 56 57 -5 +9 -72 -86 -5 +73 +91 +9 -91 +92 415 -5 +9 416 -472 -5 +489 +9 -478 -479 -2 +489 +490 +4 @@ -23222,42 +23617,37 @@ 1 2 -200 +472 2 3 -742 +1568 3 4 -45 +87 4 -5 -115 - - -5 6 -22 +267 6 7 -147 +287 7 -15 -112 +16 +228 -15 +16 73 -62 +112 @@ -23273,32 +23663,32 @@ 1 2 -280 +628 2 3 -726 +1539 3 4 -125 +243 4 5 -142 +272 5 10 -125 +243 10 24 -47 +97 @@ -23314,32 +23704,32 @@ 1 2 -280 +628 2 3 -729 +1543 3 4 -122 +238 4 5 -142 +272 5 9 -115 +228 9 22 -57 +112 @@ -23355,27 +23745,27 @@ 1 2 -945 +2021 2 3 -203 +418 3 4 -150 +292 4 -5 -112 +6 +243 -5 +8 39 -37 +48 @@ -23391,42 +23781,37 @@ 1 2 -200 +472 2 3 -742 +1568 3 4 -45 +87 4 -5 -115 - - -5 6 -22 +267 6 7 -147 +287 7 -15 -112 +16 +228 -15 +16 73 -62 +112 @@ -23442,32 +23827,32 @@ 1 2 -383 +793 2 3 -190 +370 3 5 -62 +121 5 8 -65 +126 8 18 -65 +126 -18 -1167 -42 +19 +1227 +82 @@ -23483,27 +23868,27 @@ 1 2 -596 +1207 2 3 -77 +150 3 5 -60 +116 5 13 -70 +131 13 18 -5 +14 @@ -23519,27 +23904,27 @@ 1 2 -596 +1207 2 3 -82 +160 3 5 -65 +126 5 14 -62 +121 15 16 -2 +4 @@ -23555,22 +23940,22 @@ 1 2 -626 +1266 2 3 -62 +121 3 6 -65 +126 6 -463 -55 +501 +107 @@ -23586,32 +23971,32 @@ 1 2 -383 +793 2 3 -190 +370 3 5 -62 +121 5 8 -65 +126 8 18 -65 +126 -18 -1107 -42 +19 +1137 +82 @@ -23627,12 +24012,12 @@ 1 2 -5828 +11509 2 -21 -75 +26 +146 @@ -23648,7 +24033,7 @@ 1 2 -5903 +11655 @@ -23664,7 +24049,7 @@ 1 2 -5903 +11655 @@ -23680,12 +24065,12 @@ 1 2 -5828 +11509 2 -21 -75 +26 +146 @@ -23701,12 +24086,12 @@ 1 2 -5873 +11596 2 -21 -30 +22 +58 @@ -23716,15 +24101,15 @@ operator_location -11639 +22756 id -1989 +5763 loc -1713 +3229 @@ -23738,47 +24123,32 @@ 1 2 -438 +858 2 3 -221 +3220 3 -6 -182 - - -6 -7 -41 - - -7 -8 -257 - - -8 9 -122 +395 9 -10 -495 +11 +459 -10 +11 12 -119 +595 12 -13 -108 +14 +233 @@ -23794,22 +24164,17 @@ 1 2 -1403 +2830 2 -3 -115 +9 +242 -3 -15 -131 - - -21 -793 -63 +9 +2695 +156 @@ -23819,15 +24184,15 @@ constant_value -95257 +185350 id -95199 +185238 value -24531 +47853 @@ -23841,12 +24206,12 @@ 1 2 -95141 +185126 2 3 -57 +112 @@ -23862,27 +24227,27 @@ 1 2 -16848 +32891 2 3 -3705 +7218 3 4 -1995 +3886 4 -60 -1842 +61 +3589 -60 +61 2421 -140 +267 @@ -23892,27 +24257,27 @@ methods -549172 +1117636 id -549172 +1117636 name -68273 +133590 declaring_type_id -101140 +202387 type_id -54054 +112876 unbound_id -357745 +696553 @@ -23926,7 +24291,7 @@ 1 2 -549172 +1117636 @@ -23942,7 +24307,7 @@ 1 2 -549172 +1117636 @@ -23958,7 +24323,7 @@ 1 2 -549172 +1117636 @@ -23974,7 +24339,7 @@ 1 2 -549172 +1117636 @@ -23990,32 +24355,32 @@ 1 2 -35183 +69142 2 3 -12138 +23617 3 4 -5557 +10832 4 6 -5404 +10423 6 12 -5429 +10569 12 -5061 -4559 +5621 +9005 @@ -24031,32 +24396,32 @@ 1 2 -40500 +79512 2 3 -9934 +19341 3 4 -5820 +11314 4 7 -5698 +11046 7 -32 -5131 +33 +10106 -32 -4959 -1188 +33 +5029 +2269 @@ -24072,22 +24437,22 @@ 1 2 -57652 +112856 2 3 -5432 +10593 3 -126 -5121 +174 +10023 -137 -2143 -67 +177 +2703 +116 @@ -24103,32 +24468,32 @@ 1 2 -36040 +70881 2 3 -12589 +24484 3 4 -5607 +10905 4 6 -5512 +10720 6 12 -5149 +10028 12 4958 -3374 +6570 @@ -24144,42 +24509,42 @@ 1 2 -30224 +59752 2 3 -21964 +42983 3 4 -15156 +31619 4 5 -7172 +14251 5 6 -7264 +14787 6 10 -8104 +16097 10 23 -7831 +15654 23 -1055 -3421 +1309 +7242 @@ -24195,37 +24560,37 @@ 1 2 -32832 +64817 2 3 -22819 +44668 3 4 -16580 +34717 4 5 -9122 +18191 5 8 -8951 +18157 8 18 -7600 +15249 18 457 -3233 +6585 @@ -24241,32 +24606,32 @@ 1 2 -49695 +97825 2 3 -23712 +49231 3 4 -11686 +22945 4 5 -5946 +11621 5 -11 -7863 +10 +15205 -11 -595 -2236 +10 +738 +5557 @@ -24282,42 +24647,42 @@ 1 2 -30277 +59859 2 3 -21994 +43060 3 4 -15158 +31619 4 5 -7184 +14285 5 6 -7267 +14806 6 10 -8069 +16014 10 23 -8069 +16111 23 698 -3118 +6628 @@ -24333,27 +24698,27 @@ 1 2 -35802 +75435 2 3 -6943 +14480 3 4 -4078 +8309 4 -9 -4086 +10 +8825 -9 -59685 -3143 +10 +62283 +5825 @@ -24369,22 +24734,22 @@ 1 2 -43794 +91567 2 3 -4717 +9614 3 -9 -4203 +8 +8664 -9 -7612 -1338 +8 +7666 +3029 @@ -24400,22 +24765,22 @@ 1 2 -41733 +87393 2 3 -6603 +13978 3 -7 -4101 +8 +8801 -7 -19179 -1616 +8 +19699 +2703 @@ -24431,27 +24796,27 @@ 1 2 -35852 +75547 2 3 -6984 +14538 3 4 -4103 +8382 4 -9 -4061 +10 +8762 -9 -44405 -3053 +10 +44480 +5645 @@ -24467,12 +24832,12 @@ 1 2 -344231 +669658 2 -1207 -13514 +1367 +26895 @@ -24488,7 +24853,7 @@ 1 2 -357745 +696553 @@ -24504,12 +24869,12 @@ 1 2 -345048 +671523 2 -1207 -12697 +1367 +25029 @@ -24525,12 +24890,12 @@ 1 2 -352528 +686189 2 -1207 -5216 +1367 +10364 @@ -24540,15 +24905,15 @@ method_location -622013 +1281341 id -549172 +1117636 loc -15472 +40830 @@ -24562,17 +24927,17 @@ 1 2 -488331 +987264 2 3 -49469 +98264 3 119 -11371 +32106 @@ -24588,17 +24953,17 @@ 1 2 -13409 +36217 2 -37 -1160 +51 +3078 -37 -23908 -902 +51 +27732 +1534 @@ -24608,23 +24973,23 @@ constructors -138720 +277979 id -138720 +277979 name -68664 +133464 declaring_type_id -107588 +212319 unbound_id -114690 +223248 @@ -24638,7 +25003,7 @@ 1 2 -138720 +277979 @@ -24654,7 +25019,7 @@ 1 2 -138720 +277979 @@ -24670,7 +25035,7 @@ 1 2 -138720 +277979 @@ -24686,22 +25051,22 @@ 1 2 -52686 +102185 2 3 -9766 +19170 3 8 -5271 +10247 8 2183 -940 +1860 @@ -24717,17 +25082,17 @@ 1 2 -63031 +122480 2 11 -5181 +10082 11 2183 -451 +901 @@ -24743,22 +25108,22 @@ 1 2 -53132 +103066 2 3 -9846 +19326 3 10 -5179 +10087 10 2183 -506 +983 @@ -24774,17 +25139,17 @@ 1 2 -91484 +179651 2 3 -9914 +19750 3 20 -6189 +12916 @@ -24800,7 +25165,7 @@ 1 2 -107588 +212319 @@ -24816,17 +25181,17 @@ 1 2 -91484 +179651 2 3 -9914 +19750 3 20 -6189 +12916 @@ -24842,12 +25207,12 @@ 1 2 -113489 +220793 2 -612 -1200 +780 +2454 @@ -24863,7 +25228,7 @@ 1 2 -114690 +223248 @@ -24879,12 +25244,12 @@ 1 2 -113489 +220793 2 -612 -1200 +780 +2454 @@ -24894,15 +25259,15 @@ constructor_location -159509 +321707 id -138720 +277979 loc -10914 +24771 @@ -24916,17 +25281,17 @@ 1 2 -120137 +238659 2 3 -17760 +37639 3 87 -822 +1680 @@ -24942,22 +25307,22 @@ 1 2 -8122 +19000 2 3 -1484 +3180 3 -38 -819 +59 +1865 -38 -3935 -488 +59 +4796 +725 @@ -24967,23 +25332,23 @@ destructors -225 +443 id -225 +443 name -213 +414 declaring_type_id -225 +443 unbound_id -220 +428 @@ -24997,7 +25362,7 @@ 1 2 -225 +443 @@ -25013,7 +25378,7 @@ 1 2 -225 +443 @@ -25029,7 +25394,7 @@ 1 2 -225 +443 @@ -25045,12 +25410,12 @@ 1 2 -203 +394 2 4 -10 +19 @@ -25066,12 +25431,12 @@ 1 2 -203 +394 2 4 -10 +19 @@ -25087,12 +25452,12 @@ 1 2 -205 +399 2 3 -7 +14 @@ -25108,7 +25473,7 @@ 1 2 -225 +443 @@ -25124,7 +25489,7 @@ 1 2 -225 +443 @@ -25140,7 +25505,7 @@ 1 2 -225 +443 @@ -25156,12 +25521,12 @@ 1 2 -218 +418 -3 +2 4 -2 +9 @@ -25177,7 +25542,7 @@ 1 2 -220 +428 @@ -25193,12 +25558,12 @@ 1 2 -218 +418 -3 +2 4 -2 +9 @@ -25208,15 +25573,15 @@ destructor_location -494 +659 id -125 +165 loc -230 +329 @@ -25230,42 +25595,47 @@ 1 2 -34 +32 2 3 -17 +44 3 4 -6 +9 4 5 -14 +16 5 6 -17 +6 6 7 -13 +29 7 9 -9 +12 9 11 -10 +12 + + +11 +12 +1 @@ -25281,27 +25651,22 @@ 1 2 -175 +259 2 3 -14 - - -3 -4 -12 - - -4 -9 19 -9 -26 -8 +3 +5 +28 + + +5 +27 +21 @@ -25311,15 +25676,15 @@ overrides -140510 +273927 id -140498 +273902 base_id -33661 +65402 @@ -25333,12 +25698,12 @@ 1 2 -140485 +273878 2 3 -12 +24 @@ -25354,32 +25719,32 @@ 1 2 -20716 +40250 2 3 -5389 +10471 3 4 -2206 +4286 4 7 -2752 +5338 7 -216 -2526 +184 +4909 -217 -1317 -70 +215 +1329 +146 @@ -25389,15 +25754,15 @@ explicitly_implements -74568 +156755 id -74568 +156755 interface_id -6111 +13282 @@ -25411,7 +25776,7 @@ 1 2 -74568 +156755 @@ -25427,37 +25792,37 @@ 1 2 -3171 +6770 2 3 -1057 +2488 3 4 -604 +1183 4 5 -210 +457 5 7 -491 +1207 7 -41 -458 +58 +998 -42 +58 7851 -117 +175 @@ -25467,23 +25832,23 @@ local_functions -488 +1801 id -488 +1801 name -271 +1034 return_type -47 +184 unbound_id -488 +1792 @@ -25497,7 +25862,7 @@ 1 2 -488 +1801 @@ -25513,7 +25878,7 @@ 1 2 -488 +1801 @@ -25529,7 +25894,7 @@ 1 2 -488 +1801 @@ -25545,22 +25910,17 @@ 1 2 -227 +892 2 3 -18 +80 3 -14 -22 - - -14 -38 -4 +137 +62 @@ -25576,12 +25936,12 @@ 1 2 -269 +1026 2 -3 -2 +4 +8 @@ -25597,22 +25957,17 @@ 1 2 -227 +894 2 3 -18 +82 3 -14 -22 - - -14 -38 -4 +137 +58 @@ -25628,27 +25983,22 @@ 1 2 -30 +128 2 3 -7 +29 3 -4 -3 +7 +15 -4 -11 -4 - - -26 -336 -3 +7 +1134 +12 @@ -25664,22 +26014,22 @@ 1 2 -33 +136 2 3 -7 +25 3 -6 -4 +9 +14 -26 -136 -3 +9 +427 +9 @@ -25695,27 +26045,22 @@ 1 2 -30 +128 2 3 -7 +30 3 -4 -3 +7 +14 -4 -11 -4 - - -26 -336 -3 +7 +1132 +12 @@ -25731,7 +26076,12 @@ 1 2 -488 +1788 + + +3 +5 +4 @@ -25747,7 +26097,7 @@ 1 2 -488 +1792 @@ -25763,7 +26113,12 @@ 1 2 -488 +1791 + + +3 +4 +1 @@ -25773,15 +26128,15 @@ local_function_stmts -488 +1792 fn -488 +1792 stmt -488 +1792 @@ -25795,7 +26150,7 @@ 1 2 -488 +1792 @@ -25811,7 +26166,7 @@ 1 2 -488 +1792 @@ -25821,31 +26176,31 @@ fields -283465 +556636 id -283465 +556636 kind -5 +9 name -111604 +218217 declaring_type_id -52465 +103919 type_id -45611 +89633 unbound_id -279953 +547985 @@ -25859,7 +26214,7 @@ 1 2 -283465 +556636 @@ -25875,7 +26230,7 @@ 1 2 -283465 +556636 @@ -25891,7 +26246,7 @@ 1 2 -283465 +556636 @@ -25907,7 +26262,7 @@ 1 2 -283465 +556636 @@ -25923,7 +26278,7 @@ 1 2 -283465 +556636 @@ -25937,14 +26292,14 @@ 12 -37974 -37975 -2 +38027 +38028 +4 -75103 -75104 -2 +76258 +76259 +4 @@ -25958,14 +26313,14 @@ 12 -17417 -17418 -2 +17662 +17663 +4 -29019 -29020 -2 +29062 +29063 +4 @@ -25979,14 +26334,14 @@ 12 -3310 -3311 -2 +3335 +3336 +4 -17817 -17818 -2 +18225 +18226 +4 @@ -26002,12 +26357,12 @@ 2463 2464 -2 +4 -16181 -16182 -2 +16391 +16392 +4 @@ -26021,14 +26376,14 @@ 12 -37962 -37963 -2 +38015 +38016 +4 -73714 -73715 -2 +74494 +74495 +4 @@ -26044,22 +26399,22 @@ 1 2 -90218 +176159 2 3 -11538 +22565 3 -15 -8500 +14 +16564 -15 +14 4800 -1346 +2927 @@ -26075,12 +26430,12 @@ 1 2 -106801 +208860 2 3 -4803 +9356 @@ -26096,22 +26451,22 @@ 1 2 -90231 +176184 2 3 -11531 +22550 3 -15 -8498 +14 +16555 -15 +14 4800 -1343 +2927 @@ -26127,17 +26482,17 @@ 1 2 -96495 +188667 2 3 -9032 +17660 3 2459 -6076 +11889 @@ -26153,22 +26508,22 @@ 1 2 -90406 +176559 2 3 -11536 +22570 3 -16 -8412 +15 +16472 -16 +15 4800 -1248 +2615 @@ -26184,42 +26539,42 @@ 1 2 -13760 +27319 2 3 -10719 +21216 3 4 -6297 +12843 4 5 -5139 +10101 5 6 -4061 +7934 6 8 -4712 +9273 8 12 -4143 +8148 12 4204 -3632 +7081 @@ -26235,12 +26590,12 @@ 1 2 -51969 +102828 2 3 -496 +1091 @@ -26256,42 +26611,42 @@ 1 2 -13760 +27319 2 3 -10721 +21221 3 4 -6299 +12848 4 5 -5136 +10096 5 6 -4061 +7934 6 8 -4715 +9278 8 12 -4143 +8148 12 4204 -3627 +7072 @@ -26307,37 +26662,37 @@ 1 2 -22594 +44526 2 3 -10699 +21269 3 4 -4720 +9707 4 5 -3742 +7364 5 6 -3141 +6161 6 -8 -3675 +9 +9590 -8 +9 132 -3893 +5299 @@ -26353,42 +26708,42 @@ 1 2 -13760 +27319 2 3 -10719 +21216 3 4 -6297 +12843 4 5 -5139 +10101 5 6 -4061 +7934 6 8 -4712 +9273 8 12 -4143 +8148 12 4204 -3632 +7081 @@ -26404,161 +26759,161 @@ 1 2 -28425 +55880 2 3 -5530 +10910 3 4 -3193 +6210 4 7 -4046 - - -7 -26 -3421 - - -26 -9160 -995 - - - - - - -type_id -kind - - -12 - - -1 -2 -44486 - - -2 -3 -1125 - - - - - - -type_id -name - - -12 - - -1 -2 -32473 - - -2 -3 -4712 - - -3 -5 -4020 - - -5 -17 -3436 - - -17 -5144 -967 - - - - - - -type_id -declaring_type_id - - -12 - - -1 -2 -34857 - - -2 -3 -5091 - - -3 -7 -3680 - - -7 -5706 -1982 - - - - - - -type_id -unbound_id - - -12 - - -1 -2 -28445 - - -2 -3 -5693 - - -3 -4 -3050 - - -4 -7 -4033 +7973 7 27 -3441 +6789 27 -9081 -947 +9294 +1870 + + + + + + +type_id +kind + + +12 + + +1 +2 +87436 + + +2 +3 +2196 + + + + + + +type_id +name + + +12 + + +1 +2 +63795 + + +2 +3 +9356 + + +3 +5 +7895 + + +5 +18 +6838 + + +18 +5214 +1748 + + + + + + +type_id +declaring_type_id + + +12 + + +1 +2 +68392 + + +2 +3 +10062 + + +3 +7 +7242 + + +7 +5816 +3935 + + + + + + +type_id +unbound_id + + +12 + + +1 +2 +55924 + + +2 +3 +11236 + + +3 +4 +5922 + + +4 +7 +7948 + + +7 +27 +6745 + + +27 +9188 +1855 @@ -26574,12 +26929,12 @@ 1 2 -279539 +547011 2 -210 -413 +234 +974 @@ -26595,7 +26950,7 @@ 1 2 -279953 +547985 @@ -26611,7 +26966,7 @@ 1 2 -279953 +547985 @@ -26627,12 +26982,12 @@ 1 2 -279539 +547011 2 -210 -413 +234 +974 @@ -26648,12 +27003,12 @@ 1 2 -279717 +547469 2 138 -235 +516 @@ -26663,15 +27018,15 @@ field_location -321998 +637390 id -279660 +549271 loc -24689 +52845 @@ -26685,17 +27040,17 @@ 1 2 -240001 +467168 2 3 -37935 +78095 3 57 -1722 +4008 @@ -26711,12 +27066,12 @@ 1 2 -23072 +49339 2 8882 -1616 +3506 @@ -26726,11 +27081,11 @@ localvars -72963 +163269 id -72963 +163269 kind @@ -26738,7 +27093,7 @@ name -9135 +22591 implicitly_typed @@ -26746,11 +27101,11 @@ type_id -3535 +7298 parent_id -72963 +163269 @@ -26764,7 +27119,7 @@ 1 2 -72963 +163269 @@ -26780,7 +27135,7 @@ 1 2 -72963 +163269 @@ -26796,7 +27151,7 @@ 1 2 -72963 +163269 @@ -26812,7 +27167,7 @@ 1 2 -72963 +163269 @@ -26828,7 +27183,7 @@ 1 2 -72963 +163269 @@ -26842,18 +27197,18 @@ 12 -3 -4 +18 +19 1 -373 -374 +799 +800 1 -72587 -72588 +162452 +162453 1 @@ -26868,18 +27223,18 @@ 12 -2 -3 +12 +13 1 -115 -116 +293 +294 1 -9057 -9058 +22378 +22379 1 @@ -26915,18 +27270,18 @@ 12 -2 -3 +10 +11 1 -8 -9 +25 +26 1 -3533 -3534 +7293 +7294 1 @@ -26941,18 +27296,18 @@ 12 -3 -4 +18 +19 1 -373 -374 +799 +800 1 -72587 -72588 +162452 +162453 1 @@ -26969,32 +27324,27 @@ 1 2 -5625 +14112 2 3 -1400 +3482 3 4 -559 +1462 4 -7 -690 +8 +1876 -7 -46 -691 - - -46 -7564 -170 +8 +15750 +1659 @@ -27010,12 +27360,12 @@ 1 2 -9096 +22499 2 3 -39 +92 @@ -27031,12 +27381,12 @@ 1 2 -8300 +19931 2 3 -835 +2660 @@ -27052,17 +27402,17 @@ 1 2 -7770 +19221 2 3 -727 +1909 3 -494 -638 +678 +1461 @@ -27078,32 +27428,27 @@ 1 2 -5625 +14112 2 3 -1400 +3482 3 4 -559 +1462 4 -7 -690 +8 +1876 -7 -46 -691 - - -46 -7564 -170 +8 +15750 +1659 @@ -27117,13 +27462,13 @@ 12 -13942 -13943 +36626 +36627 1 -59021 -59022 +126643 +126644 1 @@ -27159,13 +27504,13 @@ 12 -2512 -2513 +8549 +8550 1 -7458 -7459 +16702 +16703 1 @@ -27180,13 +27525,13 @@ 12 -1244 -1245 +2805 +2806 1 -2982 -2983 +6179 +6180 1 @@ -27201,13 +27546,13 @@ 12 -13942 -13943 +36626 +36627 1 -59021 -59022 +126643 +126644 1 @@ -27224,37 +27569,37 @@ 1 2 -1585 +3308 2 3 -519 +1138 3 4 -460 +772 4 6 -301 +624 6 11 -279 +591 11 -47 -267 +35 +548 -47 -17427 -124 +35 +37230 +317 @@ -27270,12 +27615,12 @@ 1 2 -3527 +7269 2 -3 -8 +4 +29 @@ -27291,32 +27636,32 @@ 1 2 -1956 +4172 2 3 -733 +1328 3 4 -238 +522 4 7 -310 +643 7 49 -266 +549 -51 -900 -32 +49 +1937 +84 @@ -27332,12 +27677,12 @@ 1 2 -2844 +5612 2 3 -691 +1686 @@ -27353,37 +27698,37 @@ 1 2 -1585 +3308 2 3 -519 +1138 3 4 -460 +772 4 6 -301 +624 6 11 -279 +591 11 -47 -267 +35 +548 -47 -17427 -124 +35 +37230 +317 @@ -27399,7 +27744,7 @@ 1 2 -72963 +163269 @@ -27415,7 +27760,7 @@ 1 2 -72963 +163269 @@ -27431,7 +27776,7 @@ 1 2 -72963 +163269 @@ -27447,7 +27792,7 @@ 1 2 -72963 +163269 @@ -27463,7 +27808,7 @@ 1 2 -72963 +163269 @@ -27473,15 +27818,15 @@ localvar_location -72963 +163269 id -72963 +163269 loc -72932 +163189 @@ -27495,7 +27840,7 @@ 1 2 -72963 +163269 @@ -27511,12 +27856,12 @@ 1 2 -72901 +163109 2 3 -31 +80 @@ -27526,35 +27871,35 @@ params -1189134 +2417427 id -1189134 +2417427 name -41432 +80808 type_id -164897 +330572 index -102 +199 mode -15 +29 parent_id -671887 +1369587 unbound_id -734670 +1434940 @@ -27568,7 +27913,7 @@ 1 2 -1189134 +2417427 @@ -27584,7 +27929,7 @@ 1 2 -1189134 +2417427 @@ -27600,7 +27945,7 @@ 1 2 -1189134 +2417427 @@ -27616,7 +27961,7 @@ 1 2 -1189134 +2417427 @@ -27632,7 +27977,7 @@ 1 2 -1189134 +2417427 @@ -27648,7 +27993,7 @@ 1 2 -1189134 +2417427 @@ -27664,42 +28009,42 @@ 1 2 -15950 +31113 2 3 -7116 +13851 3 4 -3622 +7057 4 5 -2469 +4836 5 7 -3409 +6648 7 13 -3534 +6896 13 41 -3123 +6078 41 -45301 -2206 +46351 +4325 @@ -27715,22 +28060,22 @@ 1 2 -32939 +64209 2 3 -4178 +8158 3 12 -3153 +6171 12 -6754 -1160 +6855 +2269 @@ -27746,22 +28091,22 @@ 1 2 -28201 +55003 2 3 -7467 +14563 3 4 -2820 +5513 4 33 -2943 +5727 @@ -27777,12 +28122,12 @@ 1 2 -38848 +75776 2 7 -2584 +5031 @@ -27798,42 +28143,42 @@ 1 2 -15950 +31113 2 3 -7116 +13851 3 4 -3622 +7057 4 5 -2469 +4836 5 7 -3409 +6648 7 13 -3534 +6896 13 41 -3123 +6078 41 -45301 -2206 +46351 +4325 @@ -27849,42 +28194,42 @@ 1 2 -16151 +31503 2 3 -7222 +14080 3 4 -3639 +7072 4 5 -2519 +4953 5 7 -3324 +6477 7 13 -3544 +6911 13 43 -3158 +6151 43 -36702 -1872 +36753 +3657 @@ -27900,27 +28245,27 @@ 1 2 -114442 +227559 2 3 -19498 +38940 3 6 -14283 +30080 6 -25 -12476 +24 +25059 -25 -47259 -4196 +24 +48952 +8932 @@ -27936,17 +28281,17 @@ 1 2 -144619 +289084 2 4 -14880 +30489 4 -2452 -5397 +2470 +10997 @@ -27962,17 +28307,17 @@ 1 2 -146130 +292148 2 3 -12346 +25073 3 36 -6420 +13350 @@ -27988,12 +28333,12 @@ 1 2 -160670 +321863 2 5 -4226 +8708 @@ -28009,27 +28354,27 @@ 1 2 -115728 +230057 2 3 -18487 +36982 3 6 -14459 +30494 6 -26 -12479 +25 +25020 -26 -38813 -3742 +25 +40409 +8017 @@ -28045,27 +28390,27 @@ 1 2 -117385 +233247 2 3 -17404 +34902 3 5 -12270 +25741 5 -17 -12554 +16 +25307 -17 -33727 -5281 +16 +33990 +11372 @@ -28081,67 +28426,67 @@ 1 2 -12 +24 2 3 -7 +14 3 15 -7 +14 16 26 -7 +14 30 35 -7 +14 40 48 -7 +14 52 71 -7 +14 81 266 -7 +14 431 785 -7 +14 986 1520 -7 +14 1960 -3510 -7 +3521 +14 -5391 -20664 -7 +5421 +21238 +14 -45851 -267875 -7 +47756 +281002 +14 @@ -28157,72 +28502,72 @@ 1 2 -12 +24 2 3 -7 +14 3 10 -7 +14 12 14 -5 +9 17 20 -7 +14 20 22 -7 +14 23 27 -7 +14 29 46 -7 +14 55 66 -7 +14 86 143 -7 +14 202 435 -7 +14 630 -1616 -7 +1620 +14 -2706 -6807 -7 +2712 +6835 +14 -8049 -8050 -2 +8088 +8089 +4 @@ -28238,77 +28583,77 @@ 1 2 -12 +24 2 3 -7 +14 3 8 -5 +9 9 11 -7 +14 11 12 -5 +9 12 13 -5 +9 13 14 -5 +9 14 20 -7 +14 23 40 -7 +14 161 418 -7 +14 558 841 -7 +14 1010 1444 -7 +14 1705 -2786 -7 +2798 +14 -4142 -15101 -7 +4226 +15732 +14 -38776 -38777 -2 +40518 +40519 +4 @@ -28324,32 +28669,32 @@ 1 2 -47 +92 2 3 -22 +43 3 4 -7 +14 4 5 -7 +14 5 6 -15 +29 6 7 -2 +4 @@ -28365,67 +28710,67 @@ 1 2 -12 +24 2 3 -7 +14 3 15 -7 +14 16 26 -7 +14 30 35 -7 +14 40 48 -7 +14 52 71 -7 +14 81 266 -7 +14 431 785 -7 +14 986 1520 -7 +14 1960 -3510 -7 +3521 +14 -5391 -20664 -7 +5421 +21238 +14 -45851 -267875 -7 +47756 +281002 +14 @@ -28441,67 +28786,67 @@ 1 2 -12 +24 2 3 -7 +14 3 15 -7 +14 16 26 -7 +14 30 35 -7 +14 40 48 -7 +14 52 70 -7 +14 79 141 -7 +14 178 266 -7 +14 334 601 -7 +14 891 -2068 -7 +2069 +14 -3523 -13842 -7 +3526 +13874 +14 -29502 -167307 -7 +29619 +168422 +14 @@ -28517,32 +28862,32 @@ 1253 1254 -2 +4 -2018 -2019 -2 +2019 +2020 +4 -2317 -2318 -2 +2345 +2346 +4 -6844 -6845 -2 +7103 +7104 +4 -10051 -10052 -2 +10553 +10554 +4 -451874 -451875 -2 +473058 +473059 +4 @@ -28558,32 +28903,32 @@ 110 111 -2 +4 244 245 -2 +4 -282 -283 -2 +283 +284 +4 524 525 -2 +4 -1118 -1119 -2 +1119 +1120 +4 -15568 -15569 -2 +15632 +15633 +4 @@ -28599,32 +28944,32 @@ 227 228 -2 +4 -257 -258 -2 +258 +259 +4 -358 -359 -2 +370 +371 +4 -1180 -1181 -2 +1224 +1225 +4 -3107 -3108 -2 +3184 +3185 +4 -62478 -62479 -2 +64542 +64543 +4 @@ -28640,32 +28985,32 @@ 1 2 -2 +4 8 9 -2 +4 10 11 -2 +4 12 13 -2 +4 22 23 -2 +4 41 42 -2 +4 @@ -28681,32 +29026,32 @@ 1100 1101 -2 +4 -1880 -1881 -2 +1881 +1882 +4 -2317 -2318 -2 +2345 +2346 +4 -5409 -5410 -2 +5653 +5654 +4 -10051 -10052 -2 +10553 +10554 +4 -261309 -261310 -2 +274200 +274201 +4 @@ -28722,32 +29067,32 @@ 1167 1168 -2 +4 1568 1569 -2 +4 -1959 -1960 -2 +1960 +1961 +4 -6113 -6114 -2 +6114 +6115 +4 -8393 -8394 -2 +8401 +8402 +4 -273867 -273868 -2 +275403 +275404 +4 @@ -28763,27 +29108,27 @@ 1 2 -396310 +804500 2 3 -160705 +332632 3 4 -63147 +129187 4 -15 -50643 +17 +102754 -15 +17 42 -1080 +511 @@ -28799,27 +29144,27 @@ 1 2 -396310 +804500 2 3 -160705 +332632 3 4 -63147 +129187 4 -15 -50643 +17 +102754 -15 +17 42 -1080 +511 @@ -28835,22 +29180,22 @@ 1 2 -420682 +854049 2 3 -161091 +332929 3 4 -55521 +113275 4 23 -34591 +69332 @@ -28866,27 +29211,27 @@ 1 2 -396310 +804500 2 3 -160705 +332632 3 4 -63147 +129187 4 -15 -50643 +17 +102754 -15 +17 42 -1080 +511 @@ -28902,12 +29247,12 @@ 1 2 -637849 +1301082 2 4 -34037 +68504 @@ -28923,27 +29268,27 @@ 1 2 -396310 +804500 2 3 -160705 +332632 3 4 -63147 +129187 4 -15 -50643 +17 +102754 -15 +17 42 -1080 +511 @@ -28959,12 +29304,12 @@ 1 2 -709316 +1384661 2 -10857 -25354 +11328 +50279 @@ -28980,7 +29325,7 @@ 1 2 -734670 +1434940 @@ -28996,12 +29341,12 @@ 1 2 -725656 +1416836 2 -3610 -9014 +3718 +18104 @@ -29017,7 +29362,7 @@ 1 2 -734670 +1434940 @@ -29033,7 +29378,7 @@ 1 2 -734670 +1434940 @@ -29049,12 +29394,12 @@ 1 2 -709316 +1384661 2 -10857 -25354 +11328 +50279 @@ -29064,15 +29409,15 @@ param_location -1316289 +2687049 id -1187548 +2413735 loc -56062 +137535 @@ -29086,17 +29431,17 @@ 1 2 -1063895 +2150616 2 3 -120308 +256315 3 60 -3344 +6804 @@ -29112,12 +29457,12 @@ 1 2 -54295 +133215 2 -88836 -1767 +99581 +4320 @@ -29127,15 +29472,15 @@ statements -472277 +982702 id -472277 +982702 kind -32 +38 @@ -29149,7 +29494,7 @@ 1 2 -472277 +982702 @@ -29163,83 +29508,83 @@ 12 -15 -36 +57 +85 2 -48 -52 +97 +148 2 -58 -110 +204 +266 2 -139 -143 +283 +308 2 -146 -218 +312 +593 2 -366 -402 +790 +820 2 -470 -471 +918 +926 2 -490 -990 +1226 +1786 2 -1105 -1370 +2200 +2468 2 -1601 -1628 +2752 +3191 2 -1877 -1904 +3456 +3580 2 -2956 -5122 +5468 +8857 2 -10374 -32130 +18283 +60466 2 -37889 -48002 +62422 +75943 2 -48236 -97276 +94725 +191608 2 -151170 -151171 +246631 +246632 1 @@ -29250,19 +29595,19 @@ stmt_parent -370789 +811174 stmt -370789 +811174 index -246 +448 parent -204384 +429777 @@ -29276,7 +29621,7 @@ 1 2 -370789 +811174 @@ -29292,7 +29637,7 @@ 1 2 -370789 +811174 @@ -29308,57 +29653,62 @@ 1 2 -35 +114 2 -4 -14 +3 +44 -4 +3 5 -45 +26 5 -11 -19 +8 +33 -11 -16 -15 +8 +9 +9 -16 -21 -22 +9 +10 +42 -21 -34 -19 +10 +26 +36 -37 -72 -19 +26 +45 +34 -78 -210 -19 +45 +95 +34 -229 -947 -19 +98 +472 +34 -1063 -135963 -16 +510 +78794 +34 + + +196048 +233227 +2 @@ -29374,57 +29724,62 @@ 1 2 -35 +114 2 -4 -14 +3 +44 -4 +3 5 -45 +26 5 -11 -19 +8 +33 -11 -16 -15 +8 +9 +9 -16 -21 -22 +9 +10 +42 -21 -34 -19 +10 +26 +36 -37 -72 -19 +26 +45 +34 -78 -210 -19 +45 +95 +34 -229 -947 -19 +98 +472 +34 -1063 -135963 -16 +510 +78794 +34 + + +196048 +233227 +2 @@ -29440,22 +29795,22 @@ 1 2 -144057 +290998 2 3 -32560 +74368 3 5 -16168 +37451 5 -233 -11597 +361 +26959 @@ -29471,22 +29826,22 @@ 1 2 -144057 +290998 2 3 -32560 +74368 3 5 -16168 +37451 5 -233 -11597 +361 +26959 @@ -29496,11 +29851,11 @@ stmt_parent_top_level -101488 +171527 stmt -101488 +171527 index @@ -29508,7 +29863,7 @@ parent -83071 +125712 @@ -29522,7 +29877,7 @@ 1 2 -101488 +171527 @@ -29538,7 +29893,7 @@ 1 2 -101488 +171527 @@ -29552,8 +29907,8 @@ 12 -96009 -96010 +138041 +138042 1 @@ -29568,8 +29923,8 @@ 12 -78586 -78587 +101170 +101171 1 @@ -29586,17 +29941,17 @@ 1 2 -64837 +80545 2 3 -18049 +44525 3 -4 -183 +5 +641 @@ -29612,7 +29967,7 @@ 1 2 -83071 +125712 @@ -29622,15 +29977,15 @@ stmt_location -472277 +982702 id -472277 +982702 loc -470073 +979818 @@ -29644,7 +29999,7 @@ 1 2 -472277 +982702 @@ -29660,12 +30015,12 @@ 1 2 -467869 +976934 2 3 -2203 +2884 @@ -29675,15 +30030,15 @@ catch_type -1719 +3419 catch_id -1719 +3419 type_id -79 +129 kind @@ -29701,7 +30056,7 @@ 1 2 -1719 +3419 @@ -29717,7 +30072,7 @@ 1 2 -1719 +3419 @@ -29733,52 +30088,47 @@ 1 2 -16 +32 2 3 -15 +22 3 4 -9 +11 4 5 -5 +12 5 -7 -3 +8 +9 -7 -9 -6 +8 +13 +11 -10 -15 -6 +13 +24 +9 -15 -28 -6 +27 +47 +9 -29 -144 -6 - - -203 -316 -3 +48 +702 +9 @@ -29794,7 +30144,7 @@ 1 2 -79 +129 @@ -29808,13 +30158,13 @@ 12 -278 -279 +492 +493 1 -1349 -1350 +2260 +2261 1 @@ -29834,8 +30184,8 @@ 1 -74 -75 +103 +104 1 @@ -29845,20 +30195,244 @@ +foreach_stmt_info +5338 + + +id +5338 + + +kind +9 + + + + +id +kind + + +12 + + +1 +2 +5338 + + + + + + +kind +id + + +12 + + +13 +14 +4 + + +1083 +1084 +4 + + + + + + + + +foreach_stmt_desugar +26642 + + +id +5338 + + +symbol +5118 + + +kind +24 + + + + +id +symbol + + +12 + + +4 +5 +48 + + +5 +6 +5289 + + + + + + +id +kind + + +12 + + +4 +5 +48 + + +5 +6 +5289 + + + + + + +symbol +id + + +12 + + +1 +2 +3097 + + +2 +3 +857 + + +3 +4 +370 + + +4 +7 +414 + + +7 +1074 +379 + + + + + + +symbol +kind + + +12 + + +1 +2 +5118 + + + + + + +kind +id + + +12 + + +1086 +1087 +4 + + +1096 +1097 +19 + + + + + + +kind +symbol + + +12 + + +2 +3 +4 + + +85 +86 +4 + + +318 +319 +4 + + +320 +321 +4 + + +326 +327 +4 + + + + + + + + expressions -1967906 +4249848 id -1967906 +4249848 kind -112 +132 type_id -15377 +33337 @@ -29872,7 +30446,7 @@ 1 2 -1967906 +4249848 @@ -29888,7 +30462,7 @@ 1 2 -1967906 +4249848 @@ -29902,74 +30476,64 @@ 12 -3 -17 -8 +1 +39 +11 -18 -61 -8 +43 +148 +11 -61 -134 -8 +174 +371 +11 -145 -243 -8 +409 +693 +11 -250 -457 -8 +696 +1145 +11 -532 -643 -8 +1194 +1938 +11 -661 -1291 -8 +1945 +3489 +11 -1313 -2180 -8 +3723 +7222 +11 -2252 -3767 -8 +7548 +12815 +11 -4681 -6580 -8 +13024 +36215 +11 -7133 -22007 -8 +37825 +155093 +11 -22297 -62473 -8 - - -72642 -169972 -8 - - -174284 -252450 -2 +212653 +415548 +9 @@ -29985,57 +30549,52 @@ 1 2 -31 +37 2 -4 -8 - - -5 -8 -9 +6 +11 8 -16 -8 +10 +11 -16 -37 -8 +11 +25 +11 -38 -71 -8 +33 +70 +11 -77 -137 -8 +70 +174 +11 -137 -337 -8 +195 +312 +11 -384 -790 -8 +369 +870 +11 -1764 -3948 -8 +940 +7017 +11 -4410 -7388 -3 +7043 +10152 +6 @@ -30051,67 +30610,57 @@ 1 2 -2149 +7041 2 3 -1894 +3514 3 4 -786 +2355 4 5 -984 +1973 5 -6 -970 +7 +2941 -6 -8 -1167 +7 +11 +3050 -8 -12 -1337 +11 +17 +2562 -12 -19 -1299 +17 +28 +2624 -19 -30 -1215 - - -30 +28 50 -1164 +2526 50 -113 -1161 +129 +2501 -113 -1379 -1154 - - -1383 -318203 -93 +129 +637120 +2246 @@ -30127,42 +30676,42 @@ 1 2 -5687 +13053 2 3 -2551 +4824 3 4 -1979 +4688 4 5 -1305 +2594 5 6 -933 +2037 6 8 -1320 +2775 8 12 -1227 +2524 12 57 -372 +837 @@ -30172,19 +30721,19 @@ expr_parent -1745009 +3919489 expr -1745009 +3919489 index -11825 +81443 parent -1152644 +2571970 @@ -30198,7 +30747,7 @@ 1 2 -1745009 +3919489 @@ -30214,7 +30763,7 @@ 1 2 -1745009 +3919489 @@ -30230,47 +30779,22 @@ 1 2 -3162 +67541 2 -3 -439 - - -3 -4 -1589 - - -4 -5 -186 - - -5 6 -1234 +6323 6 -7 -2909 +13 +6164 -8 -10 -1020 - - -10 -18 -895 - - -18 -837462 -387 +13 +1590335 +1414 @@ -30286,47 +30810,22 @@ 1 2 -3162 +67541 2 -3 -439 - - -3 -4 -1589 - - -4 -5 -186 - - -5 6 -1234 +6323 6 -7 -2909 +13 +6164 -8 -10 -1020 - - -10 -18 -895 - - -18 -837462 -387 +13 +1590335 +1414 @@ -30342,17 +30841,17 @@ 1 2 -726174 +1616500 2 3 -372615 +828257 3 -11185 -53853 +65537 +127211 @@ -30368,17 +30867,17 @@ 1 2 -726174 +1616500 2 3 -372615 +828257 3 -11185 -53853 +65537 +127211 @@ -30388,19 +30887,19 @@ expr_parent_top_level -239881 +500059 expr -239881 +500059 index -22 +43 parent -204873 +431875 @@ -30414,7 +30913,7 @@ 1 2 -239881 +500059 @@ -30430,7 +30929,7 @@ 1 2 -239881 +500059 @@ -30446,47 +30945,47 @@ 2 3 -2 +4 43 44 -2 +4 113 114 -2 +4 -125 -126 -2 +166 +167 +4 250 251 -2 +4 884 885 -2 +4 -4456 -4457 -2 +4465 +4466 +4 -8335 -8336 -2 +8472 +8473 +4 -81483 -81484 -2 +88274 +88275 +4 @@ -30502,47 +31001,47 @@ 2 3 -2 +4 43 44 -2 +4 113 114 -2 +4 -125 -126 -2 +166 +167 +4 250 251 -2 +4 884 885 -2 +4 -4456 -4457 -2 +4465 +4466 +4 -8335 -8336 -2 +8472 +8473 +4 -81419 -81420 -2 +88210 +88211 +4 @@ -30558,17 +31057,17 @@ 1 2 -184342 +391863 2 4 -18284 +35647 4 9 -2246 +4364 @@ -30584,17 +31083,17 @@ 1 2 -184435 +392043 2 4 -18222 +35526 4 9 -2216 +4305 @@ -30604,490 +31103,55 @@ implicitly_typed_array_creation -3866 +10813 id -3866 +10813 explicitly_sized_array_creation -1913 +4258 id -1913 +4258 stackalloc_array_creation -170 +830 id -170 +830 implicitly_typed_object_creation -405 +769 id -405 +769 mutator_invocation_mode -2 +4 id -2 - - -mode -2 - - - - -id -mode - - -12 - - -1 -2 -2 - - - - - - -mode -id - - -12 - - -1 -2 -2 - - - - - - - - -expr_compiler_generated -759849 - - -id -759849 - - - - - -expr_value -719515 - - -id -719515 - - -value -52225 - - - - -id -value - - -12 - - -1 -2 -719515 - - - - - - -value -id - - -12 - - -1 -2 -36487 - - -2 -3 -6531 - - -3 -5 -4017 - - -5 -25 -3927 - - -25 -148925 -1263 - - - - - - - - -expr_call -304738 - - -caller_id -304738 - - -target_id -22603 - - - - -caller_id -target_id - - -12 - - -1 -2 -304738 - - - - - - -target_id -caller_id - - -12 - - -1 -2 -12775 - - -2 -3 -3512 - - -3 -4 -1884 - - -4 -7 -1846 - - -7 -24 -1714 - - -24 -23696 -872 - - - - - - - - -expr_access -603781 - - -accesser_id -603781 - - -target_id -151428 - - - - -accesser_id -target_id - - -12 - - -1 -2 -603781 - - - - - - -target_id -accesser_id - - -12 - - -1 -2 -49895 - - -2 -3 -33117 - - -3 -4 -23450 - - -4 -5 -14681 - - -5 -6 -8746 - - -6 -10 -12743 - - -10 -4570 -8794 - - - - - - - - -expr_location -1970785 - - -id -1970785 - - -loc -1481488 - - - - -id -loc - - -12 - - -1 -2 -1970785 - - - - - - -loc -id - - -12 - - -1 -2 -1266804 - - -2 -3 -207105 - - -3 -62488 -7578 - - - - - - - - -dynamic_member_name -6116 - - -id -6116 - - -name -629 - - - - -id -name - - -12 - - -1 -2 -6116 - - - - - - -name -id - - -12 - - -1 -2 -172 - - -2 -3 -107 - - -3 -4 -82 - - -4 -5 -50 - - -5 -7 -47 - - -7 -11 -50 - - -11 -18 -50 - - -18 -47 -50 - - -70 -303 -17 - - - - - - - - -conditional_access -1323 - - -id -1323 - - - - - -expr_argument -409033 - - -id -409033 +4 mode @@ -31105,7 +31169,7 @@ 1 2 -409033 +4 @@ -31119,24 +31183,9 @@ 12 -93 -94 -1 - - -764 -765 -1 - - -1980 -1981 -1 - - -406196 -406197 -1 +1 +2 +4 @@ -31145,16 +31194,304 @@ -expr_argument_name -27657 +expr_compiler_generated +1629608 id -27657 +1629608 + + + + + +expr_value +1399039 + + +id +1399039 + + +value +102863 + + + + +id +value + + +12 + + +1 +2 +1399039 + + + + + + +value +id + + +12 + + +1 +2 +72292 + + +2 +3 +14945 + + +3 +6 +7875 + + +6 +2259 +7715 + + +2294 +272384 +36 + + + + + + + + +expr_call +677208 + + +caller_id +677208 + + +target_id +53760 + + + + +caller_id +target_id + + +12 + + +1 +2 +677208 + + + + + + +target_id +caller_id + + +12 + + +1 +2 +28797 + + +2 +3 +10035 + + +3 +4 +4354 + + +4 +7 +4652 + + +7 +24 +4067 + + +24 +43831 +1855 + + + + + + + + +expr_access +1375134 + + +accesser_id +1375134 + + +target_id +338201 + + + + +accesser_id +target_id + + +12 + + +1 +2 +1375134 + + + + + + +target_id +accesser_id + + +12 + + +1 +2 +110095 + + +2 +3 +71039 + + +3 +4 +54599 + + +4 +5 +33048 + + +5 +6 +19820 + + +6 +9 +25648 + + +9 +7782 +23949 + + + + + + + + +expr_location +4249848 + + +id +4249848 + + +loc +3325383 + + + + +id +loc + + +12 + + +1 +2 +4249848 + + + + + + +loc +id + + +12 + + +1 +2 +2815023 + + +2 +3 +493349 + + +3 +105362 +17010 + + + + + + + + +dynamic_member_name +13627 + + +id +13627 name -1049 +1407 @@ -31168,7 +31505,7 @@ 1 2 -27657 +13627 @@ -31184,47 +31521,204 @@ 1 2 -344 +409 2 3 -172 +248 3 4 -101 +160 4 5 -71 +112 + + +5 +7 +116 + + +7 +11 +121 + + +11 +19 +107 + + +20 +97 +107 + + +122 +304 +24 + + + + + + + + +conditional_access +3073 + + +id +3073 + + + + + +expr_argument +897951 + + +id +897951 + + +mode +4 + + + + +id +mode + + +12 + + +1 +2 +897951 + + + + + + +mode +id + + +12 + + +213 +214 +1 + + +4293 +4294 +1 + + +5669 +5670 +1 + + +887776 +887777 +1 + + + + + + + + +expr_argument_name +60805 + + +id +60805 + + +name +2738 + + + + +id +name + + +12 + + +1 +2 +60805 + + + + + + +name +id + + +12 + + +1 +2 +895 + + +2 +3 +486 + + +3 +4 +281 + + +4 +5 +195 5 8 -96 +251 8 13 -89 +232 13 -26 -81 +28 +207 -26 -187 -79 - - -212 -4751 -16 +28 +11230 +191 @@ -31282,11 +31776,11 @@ xmlDTDs -5 +6 id -5 +6 root @@ -31302,7 +31796,7 @@ fileid -5 +6 @@ -31316,7 +31810,7 @@ 1 2 -5 +6 @@ -31332,7 +31826,7 @@ 1 2 -5 +6 @@ -31348,7 +31842,7 @@ 1 2 -5 +6 @@ -31364,7 +31858,7 @@ 1 2 -5 +6 @@ -31582,7 +32076,7 @@ 1 2 -5 +6 @@ -31598,7 +32092,7 @@ 1 2 -5 +6 @@ -31614,7 +32108,7 @@ 1 2 -5 +6 @@ -31630,7 +32124,7 @@ 1 2 -5 +6 @@ -35693,11 +36187,11 @@ commentline -94236 +419593 id -94236 +419593 kind @@ -35705,11 +36199,11 @@ text -52841 +201215 rawtext -53561 +203884 @@ -35723,7 +36217,7 @@ 1 2 -94236 +419593 @@ -35739,7 +36233,7 @@ 1 2 -94236 +419593 @@ -35755,7 +36249,7 @@ 1 2 -94236 +419593 @@ -35769,18 +36263,18 @@ 12 -604 -605 +18162 +18163 1 -7127 -7128 +152161 +152162 1 -81418 -81419 +167355 +167356 1 @@ -35795,18 +36289,18 @@ 12 -156 -157 +12037 +12038 1 -4531 -4532 +60681 +60682 1 -45654 -45655 +90120 +90121 1 @@ -35821,18 +36315,18 @@ 12 -157 -158 +12704 +12705 1 -4678 -4679 +60920 +60921 1 -45835 -45836 +90457 +90458 1 @@ -35849,17 +36343,17 @@ 1 2 -44757 +164841 2 3 -5919 +23991 3 -6105 -2164 +24462 +12382 @@ -35875,12 +36369,12 @@ 1 2 -52470 +200103 2 4 -371 +1112 @@ -35896,12 +36390,12 @@ 1 2 -52264 +199092 2 -35 -577 +51 +2122 @@ -35917,17 +36411,17 @@ 1 2 -45738 +168234 2 3 -5679 +23515 3 -5512 -2143 +24457 +12133 @@ -35943,7 +36437,7 @@ 1 2 -53561 +203884 @@ -35959,7 +36453,7 @@ 1 2 -53561 +203884 @@ -35969,15 +36463,15 @@ commentline_location -94236 +419593 id -94236 +419593 loc -94236 +419593 @@ -35991,7 +36485,7 @@ 1 2 -94236 +419593 @@ -36007,7 +36501,7 @@ 1 2 -94236 +419593 @@ -36017,26 +36511,26 @@ commentblock -42325 +147802 id -42325 +147802 commentblock_location -42325 +147802 id -42325 +147802 loc -42325 +147802 @@ -36050,7 +36544,7 @@ 1 2 -42325 +147802 @@ -36066,7 +36560,7 @@ 1 2 -42325 +147802 @@ -36076,15 +36570,15 @@ commentblock_binding -133597 +511943 id -42288 +147743 entity -65144 +220972 bindtype @@ -36102,22 +36596,22 @@ 1 2 -9049 +18478 2 3 -10673 +29773 3 4 -22336 +99191 4 7 -228 +299 @@ -36133,22 +36627,22 @@ 1 2 -7568 +13258 2 3 -1533 +5343 3 4 -10676 +29728 4 5 -22509 +99412 @@ -36164,17 +36658,17 @@ 1 2 -50257 +161677 2 3 -10921 +43223 3 -525 -3965 +9897 +16071 @@ -36190,22 +36684,22 @@ 1 2 -32218 +96451 2 3 -25063 +94876 3 4 -7689 +28747 4 5 -173 +897 @@ -36219,23 +36713,23 @@ 12 -23541 -23542 +84123 +84124 1 -32035 -32036 +104686 +104687 1 -32822 -32823 +108160 +108161 1 -37140 -37141 +114096 +114097 1 @@ -36250,23 +36744,23 @@ 12 -15869 -15870 +35989 +35990 1 -21711 -21712 +77578 +77579 1 -29111 -29112 +86538 +86539 1 -33686 -33687 +102518 +102519 1 @@ -36277,19 +36771,19 @@ commentblock_child -132682 +555877 id -42325 +147802 commentline -94161 +419504 index -1200 +5092 @@ -36303,22 +36797,32 @@ 1 2 -26814 +78982 2 3 -9030 +20337 3 +4 +19370 + + +4 5 -3555 +9150 5 -1136 -2923 +8 +11712 + + +8 +4098 +8249 @@ -36334,27 +36838,37 @@ 1 2 -2277 +4380 2 3 -24975 +75536 3 4 -8866 +22212 4 +5 +17481 + + +5 6 -3376 +8801 6 -1137 -2828 +9 +11424 + + +9 +4099 +7966 @@ -36370,7 +36884,12 @@ 1 2 -94161 +419496 + + +2 +3 +8 @@ -36386,12 +36905,12 @@ 1 2 -55641 +283141 2 3 -38520 +136363 @@ -36407,47 +36926,32 @@ 1 2 -286 +2272 2 -6 -71 +3 +1407 -6 +3 7 -300 +406 7 10 -77 - - -10 -11 -145 +448 11 -15 -64 +28 +387 -15 -17 -101 - - -17 -40 -99 - - -40 -40041 -53 +28 +118949 +168 @@ -36463,47 +36967,32 @@ 1 2 -286 +2272 2 -6 -71 +3 +1407 -6 +3 7 -300 +406 7 10 -77 - - -10 -11 -145 +448 11 -15 -64 +28 +387 -15 -17 -101 - - -17 -40 -99 - - -40 -40041 -53 +28 +118942 +168 @@ -36975,7 +37464,7 @@ name -1 +2 @@ -37003,8 +37492,13 @@ 12 -3 -4 +1 +2 +1 + + +2 +3 1 @@ -37302,7 +37796,7 @@ name -6 +3 @@ -37330,19 +37824,9 @@ 12 -1 -2 -4 - - -2 -3 -1 - - 3 4 -1 +3 @@ -37363,23 +37847,23 @@ cil_instruction -16552562 +32160402 id -16552562 +32160402 opcode -496 +964 index -171041 +332320 impl -888189 +1725686 @@ -37393,7 +37877,7 @@ 1 2 -16552562 +32160402 @@ -37409,7 +37893,7 @@ 1 2 -16552562 +32160402 @@ -37425,7 +37909,7 @@ 1 2 -16552562 +32160402 @@ -37441,72 +37925,72 @@ 1 7 -40 +77 7 42 -37 +73 46 106 -37 +73 128 302 -37 +73 304 953 -37 +73 1002 1752 -37 +73 1791 2952 -37 +73 3194 4898 -37 +73 5191 11577 -37 +73 11669 19719 -37 +73 19906 53412 -37 +73 54233 104298 -37 +73 104740 420483 -37 +73 562153 815024 -5 +9 @@ -37522,67 +38006,67 @@ 1 7 -42 +82 10 31 -37 +73 32 68 -37 +73 75 148 -37 +73 150 214 -37 +73 214 313 -40 +77 323 468 -37 +73 486 699 -37 +73 714 872 -37 +73 879 1176 -37 +73 1185 1360 -37 +73 1382 2349 -37 +73 2641 31606 -37 +73 @@ -37598,72 +38082,72 @@ 1 6 -40 +77 7 22 -37 +73 26 58 -37 +73 62 191 -37 +73 192 422 -37 +73 434 696 -37 +73 703 993 -37 +73 1012 2698 -37 +73 2754 5088 -37 +73 5150 9841 -37 +73 10112 16999 -37 +73 18955 42845 -37 +73 44005 171634 -37 +73 243198 301111 -5 +9 @@ -37679,22 +38163,22 @@ 1 2 -133975 +260304 2 11 -15742 +30587 11 25 -13115 +25482 25 354308 -8207 +15946 @@ -37710,27 +38194,27 @@ 1 2 -134281 +260898 2 3 -9097 +17675 3 5 -14782 +28721 5 160 -12829 +24927 160 169 -50 +97 @@ -37746,22 +38230,22 @@ 1 2 -133975 +260304 2 11 -15742 +30587 11 25 -13115 +25482 25 354308 -8207 +15946 @@ -37777,57 +38261,57 @@ 1 2 -43222 +83978 2 3 -129568 +251741 3 4 -170983 +332208 4 5 -100772 +195793 5 6 -55082 +107021 6 9 -81281 +157924 9 14 -77684 +150934 14 21 -68857 +133785 21 35 -67649 +131437 35 106 -66634 +129465 106 68231 -26452 +51394 @@ -37843,57 +38327,57 @@ 1 2 -43222 +83978 2 3 -129716 +252028 3 4 -174054 +338175 4 5 -123195 +239360 5 6 -68133 +132377 6 7 -49557 +96286 7 9 -76029 +147720 9 12 -66293 +128802 12 17 -69868 +135748 17 33 -67955 +132032 33 74 -20162 +39174 @@ -37909,57 +38393,57 @@ 1 2 -43222 +83978 2 3 -129568 +251741 3 4 -170983 +332208 4 5 -100772 +195793 5 6 -55082 +107021 6 9 -81281 +157924 9 14 -77684 +150934 14 21 -68857 +133785 21 35 -67649 +131437 35 106 -66634 +129465 106 68231 -26452 +51394 @@ -37969,15 +38453,15 @@ cil_jump -1031096 +2003344 instruction -1031096 +2003344 target -825801 +1604471 @@ -37991,7 +38475,7 @@ 1 2 -1031096 +2003344 @@ -38007,17 +38491,17 @@ 1 2 -715866 +1390876 2 3 -73951 +143682 3 360 -35983 +69912 @@ -38027,15 +38511,15 @@ cil_access -6137610 +11924922 instruction -6137610 +11924922 target -1371444 +2664615 @@ -38049,7 +38533,7 @@ 1 2 -6137610 +11924922 @@ -38065,37 +38549,37 @@ 1 2 -486346 +944934 2 3 -380856 +739974 3 4 -138477 +269051 4 5 -96310 +187123 5 7 -116673 +226687 7 14 -104758 +203537 14 25741 -48023 +93306 @@ -38105,15 +38589,15 @@ cil_value -969669 +1883995 instruction -969669 +1883995 value -254691 +494847 @@ -38127,7 +38611,7 @@ 1 2 -969669 +1883995 @@ -38143,27 +38627,27 @@ 1 2 -172094 +334366 2 3 -40663 +79005 3 6 -20952 +40708 6 33 -19172 +37250 33 86799 -1809 +3516 @@ -38173,19 +38657,19 @@ cil_switch -100055 +194400 instruction -12275 +23851 index -1296 +2518 target -67220 +130605 @@ -38199,47 +38683,47 @@ 3 4 -3612 +7018 4 5 -2363 +4592 5 6 -1662 +3229 6 7 -867 +1685 7 8 -742 +1441 8 11 -1110 +2157 11 17 -950 +1845 17 128 -922 +1792 141 518 -45 +87 @@ -38255,42 +38739,42 @@ 1 3 -543 +1056 3 4 -4244 +8245 4 5 -2825 +5489 5 6 -1323 +2571 6 7 -947 +1841 7 9 -874 +1699 9 14 -925 +1797 14 204 -591 +1149 @@ -38306,52 +38790,52 @@ 1 2 -12 +24 2 3 -508 +988 3 4 -25 +48 4 5 -185 +360 6 11 -105 +204 11 18 -105 +204 18 24 -97 +189 25 47 -102 +199 47 225 -97 +189 238 4898 -55 +107 @@ -38367,52 +38851,52 @@ 1 2 -20 +38 2 3 -501 +974 3 4 -50 +97 4 5 -160 +311 5 11 -105 +204 11 18 -107 +209 18 24 -105 +204 24 47 -100 +194 47 271 -97 +189 289 4830 -47 +92 @@ -38428,12 +38912,12 @@ 1 2 -66381 +128973 2 12 -839 +1631 @@ -38449,17 +38933,17 @@ 1 2 -60843 +118214 2 7 -5146 +9999 7 253 -1230 +2391 @@ -38537,15 +39021,15 @@ cil_type_location -142744 +277341 id -131230 +254970 loc -1757 +3414 @@ -38559,12 +39043,12 @@ 1 2 -119716 +232600 2 3 -11513 +22370 @@ -38580,67 +39064,67 @@ 1 2 -147 +287 2 4 -112 +219 4 6 -120 +233 6 9 -152 +297 9 13 -140 +272 13 17 -137 +267 17 23 -145 +282 23 32 -135 +263 32 43 -137 +267 43 66 -132 +258 66 110 -135 +263 112 238 -132 +258 239 2419 -125 +243 @@ -38650,15 +39134,15 @@ cil_method_location -969646 +1883951 id -924658 +1796543 loc -1609 +3126 @@ -38672,12 +39156,12 @@ 1 2 -879671 +1709135 2 3 -44987 +87407 @@ -38693,67 +39177,67 @@ 1 11 -132 +258 11 23 -125 +243 23 38 -125 +243 38 53 -130 +253 53 79 -122 +238 80 107 -122 +238 107 138 -127 +248 140 204 -125 +243 204 278 -122 +238 281 385 -122 +238 388 734 -122 +238 735 1631 -122 +238 1646 33686 -105 +204 @@ -38763,27 +39247,27 @@ cil_type -409055 +794764 id -409055 +794764 name -92151 +179043 kind -10 +19 parent -79995 +155425 sourceDecl -239129 +464610 @@ -38797,7 +39281,7 @@ 1 2 -409055 +794764 @@ -38813,7 +39297,7 @@ 1 2 -409055 +794764 @@ -38829,7 +39313,7 @@ 1 2 -409055 +794764 @@ -38845,7 +39329,7 @@ 1 2 -409055 +794764 @@ -38861,22 +39345,22 @@ 1 2 -70838 +137633 2 3 -11566 +22472 3 7 -7292 +14168 7 21324 -2454 +4768 @@ -38892,7 +39376,7 @@ 1 2 -92151 +179043 @@ -38908,17 +39392,17 @@ 1 2 -83582 +162395 2 4 -7021 +13642 4 21324 -1546 +3005 @@ -38934,17 +39418,17 @@ 1 2 -75192 +146093 2 3 -11579 +22497 3 21324 -5379 +10452 @@ -38960,22 +39444,22 @@ 123 124 -2 +4 2909 2910 -2 +4 37932 37933 -2 +4 122212 122213 -2 +4 @@ -38991,22 +39475,22 @@ 21 22 -2 +4 101 102 -2 +4 1188 1189 -2 +4 35450 35451 -2 +4 @@ -39022,22 +39506,22 @@ 1 2 -2 +4 31 32 -2 +4 11217 11218 -2 +4 21323 21324 -2 +4 @@ -39053,22 +39537,22 @@ 123 124 -2 +4 2464 2465 -2 +4 37932 37933 -2 +4 54872 54873 -2 +4 @@ -39084,27 +39568,27 @@ 1 2 -52382 +101775 2 3 -13790 +26793 3 6 -6866 +13340 6 33 -6021 +11699 33 26079 -935 +1816 @@ -39120,27 +39604,27 @@ 1 2 -52678 +102350 2 3 -14005 +27212 3 6 -6813 +13238 6 38 -6013 +11684 38 1426 -483 +940 @@ -39156,12 +39640,12 @@ 1 2 -78348 +152225 2 4 -1646 +3199 @@ -39177,27 +39661,27 @@ 1 2 -52625 +102248 2 3 -14015 +27231 3 6 -6765 +13145 6 38 -6003 +11665 38 3476 -584 +1134 @@ -39213,12 +39697,12 @@ 1 2 -225344 +437827 2 3705 -13785 +26783 @@ -39234,7 +39718,7 @@ 1 2 -239129 +464610 @@ -39250,7 +39734,7 @@ 1 2 -239129 +464610 @@ -39266,12 +39750,12 @@ 1 2 -234845 +456287 2 225 -4284 +8323 @@ -39281,15 +39765,15 @@ cil_pointer_type -308 +599 id -308 +599 pointee -308 +599 @@ -39303,7 +39787,7 @@ 1 2 -308 +599 @@ -39319,7 +39803,7 @@ 1 2 -308 +599 @@ -39329,19 +39813,19 @@ cil_array_type -7292 +14168 id -7292 +14168 element_type -7252 +14090 rank -7 +14 @@ -39355,7 +39839,7 @@ 1 2 -7292 +14168 @@ -39371,7 +39855,7 @@ 1 2 -7292 +14168 @@ -39387,12 +39871,12 @@ 1 2 -7214 +14017 2 4 -37 +73 @@ -39408,12 +39892,12 @@ 1 2 -7214 +14017 2 4 -37 +73 @@ -39429,17 +39913,17 @@ 1 2 -2 +4 16 17 -2 +4 2892 2893 -2 +4 @@ -39455,17 +39939,17 @@ 1 2 -2 +4 16 17 -2 +4 2892 2893 -2 +4 @@ -39528,23 +40012,23 @@ cil_method -1189816 +2311725 id -1189816 +2311725 name -226266 +439619 parent -195528 +379896 return_type -110065 +213848 @@ -39558,7 +40042,7 @@ 1 2 -1189816 +2311725 @@ -39574,7 +40058,7 @@ 1 2 -1189816 +2311725 @@ -39590,7 +40074,7 @@ 1 2 -1189816 +2311725 @@ -39606,27 +40090,27 @@ 1 2 -139407 +270858 2 3 -40949 +79561 3 4 -12877 +25020 4 7 -17229 +33475 7 64064 -15803 +30704 @@ -39642,27 +40126,27 @@ 1 2 -146614 +284861 2 3 -39384 +76521 3 5 -20508 +39846 5 25 -17056 +33139 25 52725 -2702 +5250 @@ -39678,17 +40162,17 @@ 1 2 -197578 +383880 2 4 -20693 +40206 4 2803 -7994 +15532 @@ -39704,42 +40188,42 @@ 1 2 -55538 +107908 2 3 -43468 +84456 3 4 -25692 +49918 4 5 -14695 +28551 5 7 -15878 +30850 7 11 -16931 +32896 11 21 -14893 +28936 21 3536 -8430 +16379 @@ -39755,42 +40239,42 @@ 1 2 -58825 +114293 2 3 -44576 +86608 3 4 -25978 +50473 4 5 -14873 +28897 5 7 -16908 +32852 7 11 -15437 +29993 11 26 -14757 +28673 26 1885 -4171 +8104 @@ -39806,32 +40290,32 @@ 1 2 -83409 +162059 2 3 -48191 +93632 3 4 -23862 +46363 4 5 -11982 +23281 5 7 -14604 +28376 7 1924 -13476 +26184 @@ -39847,27 +40331,27 @@ 1 2 -67877 +131881 2 3 -19668 +38214 3 5 -9691 +18829 5 13 -8520 +16555 13 190707 -4306 +8367 @@ -39883,22 +40367,22 @@ 1 2 -78972 +153438 2 3 -15607 +30324 3 6 -9846 +19131 6 28461 -5637 +10953 @@ -39914,22 +40398,22 @@ 1 2 -74781 +145294 2 3 -18202 +35365 3 5 -9027 +17539 5 62018 -8054 +15649 @@ -39939,15 +40423,15 @@ cil_method_source_declaration -1083735 +2105616 method -1083735 +2105616 source -958949 +1863168 @@ -39961,7 +40445,7 @@ 1 2 -1083735 +2105616 @@ -39977,12 +40461,12 @@ 1 2 -904975 +1758299 2 1021 -53974 +104868 @@ -39992,19 +40476,19 @@ cil_method_implementation -888189 +1725686 id -888189 +1725686 method -843532 +1638921 location -1591 +3092 @@ -40018,7 +40502,7 @@ 1 2 -888189 +1725686 @@ -40034,7 +40518,7 @@ 1 2 -888189 +1725686 @@ -40050,12 +40534,12 @@ 1 2 -798875 +1552156 2 3 -44656 +86764 @@ -40071,12 +40555,12 @@ 1 2 -798875 +1552156 2 3 -44656 +86764 @@ -40092,67 +40576,67 @@ 1 11 -140 +272 11 22 -122 +238 22 36 -122 +238 36 50 -120 +233 50 74 -125 +243 74 104 -127 +248 104 133 -122 +238 133 192 -120 +233 192 271 -120 +233 271 365 -127 +248 372 654 -120 +233 682 1597 -122 +238 1599 33053 -97 +189 @@ -40168,67 +40652,67 @@ 1 11 -140 +272 11 22 -122 +238 22 36 -122 +238 36 50 -120 +233 50 74 -125 +243 74 104 -127 +248 104 133 -122 +238 133 192 -120 +233 192 271 -120 +233 271 365 -127 +248 372 654 -120 +233 682 1597 -122 +238 1599 33053 -97 +189 @@ -40238,15 +40722,15 @@ cil_implements -55097 +107050 id -54706 +106291 decl -9119 +17719 @@ -40260,12 +40744,12 @@ 1 2 -54315 +105531 2 3 -391 +759 @@ -40281,27 +40765,27 @@ 1 2 -5936 +11533 2 3 -1391 +2703 3 5 -812 +1578 5 18 -684 +1329 18 2180 -295 +574 @@ -40311,23 +40795,23 @@ cil_field -518960 +1008300 id -518960 +1008300 parent -103509 +201111 name -185701 +360803 field_type -85352 +165834 @@ -40341,7 +40825,7 @@ 1 2 -518960 +1008300 @@ -40357,7 +40841,7 @@ 1 2 -518960 +1008300 @@ -40373,7 +40857,7 @@ 1 2 -518960 +1008300 @@ -40389,47 +40873,47 @@ 1 2 -31195 +60609 2 3 -21115 +41025 3 4 -11471 +22287 4 5 -7966 +15478 5 6 -6026 +11708 6 8 -8721 +16944 8 12 -9187 +17850 12 227 -7766 +15089 237 4205 -60 +116 @@ -40445,47 +40929,47 @@ 1 2 -31195 +60609 2 3 -21115 +41025 3 4 -11471 +22287 4 5 -7966 +15478 5 6 -6026 +11708 6 8 -8721 +16944 8 12 -9187 +17850 12 227 -7766 +15089 237 4205 -60 +116 @@ -40501,37 +40985,37 @@ 1 2 -36231 +70394 2 3 -30751 +59747 3 4 -10508 +20417 4 5 -5898 +11460 5 7 -8072 +15683 7 11 -8262 +16053 11 132 -3785 +7354 @@ -40547,22 +41031,22 @@ 1 2 -134749 +261809 2 3 -28485 +55344 3 7 -15474 +30066 7 5664 -6991 +13584 @@ -40578,22 +41062,22 @@ 1 2 -134749 +261809 2 3 -28485 +55344 3 7 -15474 +30066 7 5664 -6991 +13584 @@ -40609,17 +41093,17 @@ 1 2 -157161 +305352 2 3 -17525 +34050 3 2790 -11015 +21401 @@ -40635,32 +41119,32 @@ 1 2 -42515 +82605 2 3 -22521 +43757 3 4 -4610 +8957 4 7 -7851 +15254 7 31 -6452 +12536 31 21103 -1401 +2722 @@ -40676,22 +41160,22 @@ 1 2 -49760 +96681 2 3 -22894 +44483 3 6 -7322 +14227 6 12257 -5374 +10442 @@ -40707,27 +41191,27 @@ 1 2 -61655 +119792 2 3 -9242 +17957 3 5 -6813 +13238 5 20 -6414 +12463 20 8901 -1225 +2381 @@ -40737,23 +41221,23 @@ cil_parameter -2339980 +4546408 id -2339980 +4546408 parameterizable -1142723 +2220226 index -102 +199 param_type -284357 +552486 @@ -40767,7 +41251,7 @@ 1 2 -2339980 +4546408 @@ -40783,7 +41267,7 @@ 1 2 -2339980 +4546408 @@ -40799,7 +41283,7 @@ 1 2 -2339980 +4546408 @@ -40815,27 +41299,27 @@ 1 2 -463488 +900524 2 3 -405252 +787375 3 4 -167073 +324610 4 7 -90027 +174917 7 42 -16881 +32798 @@ -40851,27 +41335,27 @@ 1 2 -463488 +900524 2 3 -405252 +787375 3 4 -167073 +324610 4 7 -90027 +174917 7 42 -16881 +32798 @@ -40887,22 +41371,22 @@ 1 2 -488208 +948553 2 3 -410659 +797881 3 4 -161084 +312974 4 23 -82770 +160817 @@ -40918,67 +41402,67 @@ 1 2 -12 +24 2 3 -7 +14 3 18 -7 +14 20 35 -7 +14 44 53 -7 +14 61 78 -7 +14 87 122 -7 +14 150 293 -7 +14 378 632 -7 +14 810 2528 -7 +14 3263 6735 -7 +14 11503 42648 -7 +14 109294 455844 -7 +14 @@ -40994,67 +41478,67 @@ 1 2 -12 +24 2 3 -7 +14 3 18 -7 +14 20 35 -7 +14 44 53 -7 +14 61 78 -7 +14 87 122 -7 +14 150 293 -7 +14 378 632 -7 +14 810 2528 -7 +14 3263 6735 -7 +14 11503 42648 -7 +14 109294 455844 -7 +14 @@ -41070,72 +41554,72 @@ 1 2 -12 +24 2 3 -7 +14 3 11 -7 +14 11 16 -7 +14 16 18 -7 +14 19 21 -5 +9 22 28 -7 +14 34 88 -7 +14 129 233 -7 +14 290 447 -7 +14 554 928 -7 +14 1321 3323 -7 +14 6167 43422 -7 +14 83818 83819 -2 +4 @@ -41151,42 +41635,42 @@ 1 2 -95417 +185389 2 3 -70539 +137053 3 4 -23168 +45014 4 5 -19788 +38448 5 7 -22569 +43849 7 11 -22007 +42758 11 27 -21553 +41877 27 58010 -9312 +18094 @@ -41202,42 +41686,42 @@ 1 2 -97067 +188594 2 3 -69870 +135753 3 4 -23381 +45428 4 5 -19162 +37230 5 7 -22799 +44298 7 11 -22037 +42817 11 28 -21471 +41716 28 46068 -8568 +16647 @@ -41253,22 +41737,22 @@ 1 2 -198441 +385556 2 3 -56524 +109822 3 4 -22884 +44463 4 36 -6507 +12644 @@ -41278,37 +41762,37 @@ cil_parameter_in -16650 +32350 id -16650 +32350 cil_parameter_out -23687 +46022 id -23687 +46022 cil_setter -54944 +106753 prop -54944 +106753 method -54944 +106753 @@ -41322,7 +41806,7 @@ 1 2 -54944 +106753 @@ -41338,7 +41822,7 @@ 1 2 -54944 +106753 @@ -41348,19 +41832,19 @@ cil_custom_modifiers -2113 +4105 id -2113 +4105 modifier -27 +53 kind -2 +4 @@ -41374,7 +41858,7 @@ 1 2 -2113 +4105 @@ -41390,7 +41874,7 @@ 1 2 -2113 +4105 @@ -41406,57 +41890,57 @@ 5 6 -2 +4 10 11 -2 +4 11 12 -2 +4 19 20 -2 +4 25 26 -2 +4 29 30 -2 +4 51 52 -2 +4 68 69 -2 +4 87 88 -2 +4 94 95 -2 +4 444 445 -2 +4 @@ -41472,7 +41956,7 @@ 1 2 -27 +53 @@ -41488,7 +41972,7 @@ 843 844 -2 +4 @@ -41504,7 +41988,7 @@ 11 12 -2 +4 @@ -41514,15 +41998,15 @@ cil_type_annotation -100907 +196056 id -100907 +196056 annotation -2 +4 @@ -41536,7 +42020,7 @@ 1 2 -100907 +196056 @@ -41552,7 +42036,7 @@ 40253 40254 -2 +4 @@ -41562,15 +42046,15 @@ cil_getter -195244 +379346 prop -195244 +379346 method -195244 +379346 @@ -41584,7 +42068,7 @@ 1 2 -195244 +379346 @@ -41600,7 +42084,7 @@ 1 2 -195244 +379346 @@ -41610,15 +42094,15 @@ cil_adder -10741 +20870 event -10741 +20870 method -10741 +20870 @@ -41632,7 +42116,7 @@ 1 2 -10741 +20870 @@ -41648,7 +42132,7 @@ 1 2 -10741 +20870 @@ -41658,15 +42142,15 @@ cil_remover -10741 +20870 event -10741 +20870 method -10741 +20870 @@ -41680,7 +42164,7 @@ 1 2 -10741 +20870 @@ -41696,7 +42180,7 @@ 1 2 -10741 +20870 @@ -41754,23 +42238,23 @@ cil_property -195525 +379891 id -195525 +379891 parent -48198 +93646 name -54674 +106227 property_type -25642 +49821 @@ -41784,7 +42268,7 @@ 1 2 -195525 +379891 @@ -41800,7 +42284,7 @@ 1 2 -195525 +379891 @@ -41816,7 +42300,7 @@ 1 2 -195525 +379891 @@ -41832,42 +42316,42 @@ 1 2 -14855 +28863 2 3 -11463 +22273 3 4 -5873 +11411 4 5 -4349 +8450 5 6 -2953 +5737 6 9 -4457 +8659 9 25 -3652 +7096 25 1883 -594 +1154 @@ -41883,42 +42367,42 @@ 1 2 -17297 +33607 2 3 -9154 +17787 3 4 -5820 +11309 4 5 -4354 +8460 5 6 -2943 +5718 6 8 -3409 +6624 8 15 -3712 +7213 15 1883 -1506 +2927 @@ -41934,32 +42418,32 @@ 1 2 -18041 +35053 2 3 -13256 +25755 3 4 -6933 +13472 4 5 -4168 +8099 5 8 -3990 +7753 8 50 -1807 +3511 @@ -41975,27 +42459,27 @@ 1 2 -32232 +62626 2 3 -11030 +21430 3 4 -3334 +6477 4 8 -4507 +8757 8 2134 -3569 +6935 @@ -42011,27 +42495,27 @@ 1 2 -32232 +62626 2 3 -11067 +21503 3 4 -3321 +6453 4 8 -4514 +8771 8 1400 -3537 +6872 @@ -42047,17 +42531,17 @@ 1 2 -46012 +89399 2 3 -5645 +10968 3 568 -3015 +5859 @@ -42073,27 +42557,27 @@ 1 2 -16169 +31415 2 3 -3868 +7515 3 4 -1636 +3180 4 8 -2246 +4364 8 15452 -1722 +3346 @@ -42109,27 +42593,27 @@ 1 2 -17089 +33202 2 3 -3617 +7028 3 4 -1566 +3044 4 8 -1987 +3862 8 5858 -1381 +2683 @@ -42145,22 +42629,22 @@ 1 2 -20548 +39924 2 3 -2732 +5308 3 12 -1955 +3799 12 6253 -406 +789 @@ -42170,23 +42654,23 @@ cil_event -10726 +20841 id -10726 +20841 parent -3324 +6458 name -6723 +13062 event_type -3497 +6794 @@ -42200,7 +42684,7 @@ 1 2 -10726 +20841 @@ -42216,7 +42700,7 @@ 1 2 -10726 +20841 @@ -42232,7 +42716,7 @@ 1 2 -10726 +20841 @@ -42248,17 +42732,17 @@ 1 2 -2955 +5742 2 7 -253 +491 7 465 -115 +224 @@ -42274,17 +42758,17 @@ 1 2 -2955 +5742 2 7 -253 +491 7 465 -115 +224 @@ -42300,17 +42784,17 @@ 1 2 -3045 +5917 2 20 -250 +487 30 181 -27 +53 @@ -42326,17 +42810,17 @@ 1 2 -5998 +11655 2 4 -496 +964 4 566 -228 +443 @@ -42352,17 +42836,17 @@ 1 2 -5998 +11655 2 4 -496 +964 4 566 -228 +443 @@ -42378,12 +42862,12 @@ 1 2 -6417 +12468 2 566 -305 +594 @@ -42399,27 +42883,27 @@ 1 2 -486 +944 2 3 -2323 +4515 3 4 -300 +584 4 8 -295 +574 8 318 -90 +175 @@ -42435,17 +42919,17 @@ 1 2 -731 +1422 2 3 -2617 +5084 3 32 -147 +287 @@ -42461,27 +42945,27 @@ 1 2 -674 +1310 2 3 -2236 +4344 3 4 -255 +496 4 10 -273 +530 10 243 -57 +112 @@ -42491,23 +42975,23 @@ cil_local_variable -592197 +1150595 id -592197 +1150595 impl -179424 +348608 index -355 +691 var_type -79371 +154212 @@ -42521,7 +43005,7 @@ 1 2 -592197 +1150595 @@ -42537,7 +43021,7 @@ 1 2 -592197 +1150595 @@ -42553,7 +43037,7 @@ 1 2 -592197 +1150595 @@ -42569,37 +43053,37 @@ 1 2 -71998 +139888 2 3 -31924 +62027 3 4 -25381 +49314 4 5 -12080 +23471 5 7 -16404 +31873 7 12 -14850 +28853 12 143 -6783 +13179 @@ -42615,37 +43099,37 @@ 1 2 -71998 +139888 2 3 -31924 +62027 3 4 -25381 +49314 4 5 -12080 +23471 5 7 -16404 +31873 7 12 -14850 +28853 12 143 -6783 +13179 @@ -42661,32 +43145,32 @@ 1 2 -86641 +168337 2 3 -36085 +70112 3 4 -19523 +37932 4 5 -10623 +20641 5 7 -14238 +27664 7 47 -12311 +23919 @@ -42702,62 +43186,62 @@ 1 2 -35 +68 2 3 -45 +87 3 5 -32 +63 5 7 -25 +48 7 8 -32 +63 8 13 -32 +63 13 19 -27 +53 21 51 -27 +53 56 167 -27 +53 182 829 -27 +53 1008 8631 -27 +53 11398 71575 -15 +29 @@ -42773,62 +43257,62 @@ 1 2 -35 +68 2 3 -45 +87 3 5 -32 +63 5 7 -25 +48 7 8 -32 +63 8 13 -32 +63 13 19 -27 +53 21 51 -27 +53 56 167 -27 +53 182 829 -27 +53 1008 8631 -27 +53 11398 71575 -15 +29 @@ -42844,67 +43328,67 @@ 1 2 -37 +73 2 3 -47 +92 3 4 -30 +58 4 5 -12 +24 5 6 -30 +58 6 8 -30 +58 8 11 -22 +43 11 18 -27 +53 19 42 -27 +53 52 110 -27 +53 143 539 -27 +53 599 4919 -27 +53 7226 19498 -7 +14 @@ -42920,37 +43404,37 @@ 1 2 -41836 +81285 2 3 -14018 +27236 3 4 -4309 +8372 4 5 -6084 +11820 5 8 -6580 +12785 8 76 -5956 +11572 76 35712 -586 +1139 @@ -42966,32 +43450,32 @@ 1 2 -43909 +85313 2 3 -15943 +30976 3 4 -4314 +8382 4 5 -6021 +11699 5 14 -6186 +12020 14 21451 -2995 +5820 @@ -43007,27 +43491,27 @@ 1 2 -49725 +96613 2 3 -14757 +28673 3 4 -7086 +13769 4 9 -6104 +11859 9 122 -1697 +3297 @@ -43090,35 +43574,35 @@ cil_handler -52214 +101449 id -52214 +101449 impl -36760 +71422 index -40 +77 kind -10 +19 try_start -50239 +97611 try_end -51380 +99827 handler_start -52214 +101449 @@ -43132,7 +43616,7 @@ 1 2 -52214 +101449 @@ -43148,7 +43632,7 @@ 1 2 -52214 +101449 @@ -43164,7 +43648,7 @@ 1 2 -52214 +101449 @@ -43180,7 +43664,7 @@ 1 2 -52214 +101449 @@ -43196,7 +43680,7 @@ 1 2 -52214 +101449 @@ -43212,7 +43696,7 @@ 1 2 -52214 +101449 @@ -43228,22 +43712,22 @@ 1 2 -27677 +53776 2 3 -5740 +11153 3 5 -2792 +5425 5 17 -548 +1066 @@ -43259,22 +43743,22 @@ 1 2 -27677 +53776 2 3 -5740 +11153 3 5 -2792 +5425 5 17 -548 +1066 @@ -43290,17 +43774,17 @@ 1 2 -31839 +61861 2 3 -4805 +9336 3 4 -115 +224 @@ -43316,22 +43800,22 @@ 1 2 -28206 +54803 2 3 -5582 +10846 3 7 -2845 +5528 7 15 -125 +243 @@ -43347,22 +43831,22 @@ 1 2 -27961 +54326 2 3 -5695 +11065 3 6 -2842 +5523 6 16 -260 +506 @@ -43378,22 +43862,22 @@ 1 2 -27677 +53776 2 3 -5740 +11153 3 5 -2792 +5425 5 17 -548 +1066 @@ -43409,77 +43893,77 @@ 1 2 -2 +4 2 3 -5 +9 4 5 -2 +4 9 10 -2 +4 11 12 -2 +4 20 21 -2 +4 27 28 -2 +4 40 41 -2 +4 66 67 -2 +4 123 124 -2 +4 219 220 -2 +4 685 686 -2 +4 1333 1334 -2 +4 3623 3624 -2 +4 14664 14665 -2 +4 @@ -43495,77 +43979,77 @@ 1 2 -2 +4 2 3 -5 +9 4 5 -2 +4 9 10 -2 +4 11 12 -2 +4 20 21 -2 +4 27 28 -2 +4 40 41 -2 +4 66 67 -2 +4 123 124 -2 +4 219 220 -2 +4 685 686 -2 +4 1333 1334 -2 +4 3623 3624 -2 +4 14664 14665 -2 +4 @@ -43581,22 +44065,22 @@ 1 2 -5 +9 2 3 -15 +29 3 4 -7 +14 4 5 -12 +24 @@ -43612,77 +44096,77 @@ 1 2 -2 +4 2 3 -5 +9 4 5 -2 +4 9 10 -2 +4 11 12 -2 +4 20 21 -2 +4 27 28 -2 +4 40 41 -2 +4 66 67 -2 +4 123 124 -2 +4 219 220 -2 +4 685 686 -2 +4 1333 1334 -2 +4 3623 3624 -2 +4 14664 14665 -2 +4 @@ -43698,77 +44182,77 @@ 1 2 -2 +4 2 3 -5 +9 4 5 -2 +4 9 10 -2 +4 11 12 -2 +4 20 21 -2 +4 27 28 -2 +4 40 41 -2 +4 66 67 -2 +4 123 124 -2 +4 219 220 -2 +4 685 686 -2 +4 1333 1334 -2 +4 3623 3624 -2 +4 14664 14665 -2 +4 @@ -43784,77 +44268,77 @@ 1 2 -2 +4 2 3 -5 +9 4 5 -2 +4 9 10 -2 +4 11 12 -2 +4 20 21 -2 +4 27 28 -2 +4 40 41 -2 +4 66 67 -2 +4 123 124 -2 +4 219 220 -2 +4 685 686 -2 +4 1333 1334 -2 +4 3623 3624 -2 +4 14664 14665 -2 +4 @@ -43870,22 +44354,22 @@ 166 167 -2 +4 302 303 -2 +4 8994 8995 -2 +4 11367 11368 -2 +4 @@ -43901,22 +44385,22 @@ 148 149 -2 +4 302 303 -2 +4 7560 7561 -2 +4 8663 8664 -2 +4 @@ -43932,22 +44416,22 @@ 5 6 -2 +4 8 9 -2 +4 14 15 -2 +4 16 17 -2 +4 @@ -43963,22 +44447,22 @@ 159 160 -2 +4 302 303 -2 +4 8695 8696 -2 +4 11363 11364 -2 +4 @@ -43994,22 +44478,22 @@ 159 160 -2 +4 302 303 -2 +4 8704 8705 -2 +4 11367 11368 -2 +4 @@ -44025,22 +44509,22 @@ 166 167 -2 +4 302 303 -2 +4 8994 8995 -2 +4 11367 11368 -2 +4 @@ -44056,12 +44540,12 @@ 1 2 -48542 +94314 2 8 -1697 +3297 @@ -44077,7 +44561,7 @@ 1 2 -50239 +97611 @@ -44093,12 +44577,12 @@ 1 2 -48542 +94314 2 8 -1697 +3297 @@ -44114,12 +44598,12 @@ 1 2 -49076 +95351 2 4 -1163 +2259 @@ -44135,12 +44619,12 @@ 1 2 -49098 +95395 2 3 -1140 +2216 @@ -44156,12 +44640,12 @@ 1 2 -48542 +94314 2 8 -1697 +3297 @@ -44177,12 +44661,12 @@ 1 2 -50748 +98600 2 7 -631 +1227 @@ -44198,7 +44682,7 @@ 1 2 -51380 +99827 @@ -44214,12 +44698,12 @@ 1 2 -50748 +98600 2 7 -631 +1227 @@ -44235,12 +44719,12 @@ 1 2 -51289 +99652 2 3 -90 +175 @@ -44256,7 +44740,7 @@ 1 2 -51380 +99827 @@ -44272,12 +44756,12 @@ 1 2 -50748 +98600 2 7 -631 +1227 @@ -44293,7 +44777,7 @@ 1 2 -52214 +101449 @@ -44309,7 +44793,7 @@ 1 2 -52214 +101449 @@ -44325,7 +44809,7 @@ 1 2 -52214 +101449 @@ -44341,7 +44825,7 @@ 1 2 -52214 +101449 @@ -44357,7 +44841,7 @@ 1 2 -52214 +101449 @@ -44373,7 +44857,7 @@ 1 2 -52214 +101449 @@ -44383,15 +44867,15 @@ cil_handler_filter -416 +808 id -416 +808 filter_start -416 +808 @@ -44405,7 +44889,7 @@ 1 2 -416 +808 @@ -44421,7 +44905,7 @@ 1 2 -416 +808 @@ -44431,15 +44915,15 @@ cil_handler_type -22546 +43806 id -22546 +43806 catch_type -649 +1261 @@ -44453,7 +44937,7 @@ 1 2 -22546 +43806 @@ -44469,42 +44953,42 @@ 1 2 -225 +438 2 3 -137 +267 3 4 -77 +150 4 5 -52 +102 5 8 -50 +97 8 16 -52 +102 16 2589 -50 +97 3495 3496 -2 +4 @@ -44514,15 +44998,15 @@ cil_method_stack_size -888189 +1725686 method -888189 +1725686 size -82 +160 @@ -44536,7 +45020,7 @@ 1 2 -888189 +1725686 @@ -44552,62 +45036,62 @@ 1 2 -5 +9 4 5 -5 +9 5 7 -7 +14 7 10 -7 +14 10 14 -7 +14 14 19 -7 +14 54 75 -7 +14 99 326 -7 +14 814 2665 -7 +14 3004 5050 -7 +14 8726 20803 -7 +14 23498 270374 -5 +9 @@ -44617,110 +45101,110 @@ cil_public -982987 +1909872 id -982987 +1909872 cil_private -477765 +928262 id -477765 +928262 cil_protected -935332 +1817282 id -935332 +1817282 cil_internal -23052 +41663 id -23052 +41663 cil_static -408907 +794476 id -408907 +794476 cil_sealed -183415 +356362 id -183415 +356362 cil_virtual -348562 +677231 id -348562 +677231 cil_abstract -84971 +165093 id -84971 +165093 cil_class -122717 +238430 id -122717 +238430 cil_interface -8513 +16540 id -8513 +16540 @@ -44749,37 +45233,37 @@ cil_specialname -417180 +810549 id -417180 +810549 cil_newslot -217219 +422041 id -217219 +422041 cil_base_class -121182 +235449 id -121182 +235449 base -11012 +21396 @@ -44793,7 +45277,7 @@ 1 2 -121182 +235449 @@ -44809,32 +45293,32 @@ 1 2 -6334 +12307 2 3 -1985 +3857 3 4 -829 +1612 4 7 -972 +1889 7 84 -827 +1607 86 23834 -62 +121 @@ -44844,15 +45328,15 @@ cil_base_interface -64405 +125135 id -35286 +68558 base -16046 +31176 @@ -44866,27 +45350,27 @@ 1 2 -24534 +47668 2 3 -4173 +8109 3 5 -3221 +6258 5 9 -2765 +5372 9 25 -591 +1149 @@ -44902,27 +45386,27 @@ 1 2 -11561 +22463 2 3 -1764 +3428 3 5 -1296 +2518 5 30 -1205 +2342 30 2180 -218 +423 @@ -44932,15 +45416,15 @@ cil_enum_underlying_type -7237 +14061 id -7237 +14061 underlying -20 +38 @@ -44954,7 +45438,7 @@ 1 2 -7237 +14061 @@ -44970,42 +45454,42 @@ 5 6 -2 +4 6 7 -2 +4 25 26 -2 +4 31 32 -2 +4 41 42 -2 +4 173 174 -2 +4 291 292 -2 +4 2315 2316 -2 +4 @@ -45015,19 +45499,19 @@ cil_type_parameter -95089 +184751 unbound -53453 +103855 index -52 +102 param -95089 +184751 @@ -45041,22 +45525,22 @@ 1 2 -38572 +74943 2 3 -9774 +18990 3 13 -4196 +8153 13 22 -909 +1768 @@ -45072,22 +45556,22 @@ 1 2 -38572 +74943 2 3 -9774 +18990 3 13 -4196 +8153 13 22 -909 +1768 @@ -45103,107 +45587,107 @@ 8 9 -2 +4 14 15 -2 +4 21 22 -2 +4 27 28 -2 +4 65 66 -2 +4 132 133 -2 +4 207 208 -2 +4 285 286 -2 +4 363 364 -2 +4 441 442 -2 +4 519 520 -2 +4 598 599 -2 +4 680 681 -2 +4 791 792 -2 +4 891 892 -2 +4 1012 1013 -2 +4 1173 1174 -2 +4 1409 1410 -2 +4 2037 2038 -2 +4 5936 5937 -2 +4 21323 21324 -2 +4 @@ -45219,107 +45703,107 @@ 8 9 -2 +4 14 15 -2 +4 21 22 -2 +4 27 28 -2 +4 65 66 -2 +4 132 133 -2 +4 207 208 -2 +4 285 286 -2 +4 363 364 -2 +4 441 442 -2 +4 519 520 -2 +4 598 599 -2 +4 680 681 -2 +4 791 792 -2 +4 891 892 -2 +4 1012 1013 -2 +4 1173 1174 -2 +4 1409 1410 -2 +4 2037 2038 -2 +4 5936 5937 -2 +4 21323 21324 -2 +4 @@ -45335,7 +45819,7 @@ 1 2 -95089 +184751 @@ -45351,7 +45835,7 @@ 1 2 -95089 +184751 @@ -45361,19 +45845,19 @@ cil_type_argument -379309 +736969 bound -247697 +481258 index -52 +102 t -129781 +252155 @@ -45387,17 +45871,17 @@ 1 2 -172996 +336119 2 3 -60392 +117337 3 22 -14309 +27801 @@ -45413,17 +45897,17 @@ 1 2 -175521 +341024 2 3 -59304 +115223 3 22 -12872 +25010 @@ -45439,97 +45923,97 @@ 3 4 -5 +9 4 5 -5 +9 84 85 -2 +4 205 206 -2 +4 343 344 -2 +4 482 483 -2 +4 621 622 -2 +4 760 761 -2 +4 899 900 -2 +4 1044 1045 -2 +4 1189 1190 -2 +4 1601 1602 -2 +4 1810 1811 -2 +4 2091 2092 -2 +4 2513 2514 -2 +4 3338 3339 -2 +4 5708 5709 -2 +4 29799 29800 -2 +4 98809 98810 -2 +4 @@ -45545,97 +46029,97 @@ 3 4 -7 +14 4 5 -2 +4 49 50 -2 +4 116 117 -2 +4 185 186 -2 +4 254 255 -2 +4 322 323 -2 +4 390 391 -2 +4 457 458 -2 +4 531 532 -2 +4 602 603 -2 +4 925 926 -2 +4 927 928 -2 +4 1083 1084 -2 +4 1307 1308 -2 +4 1645 1646 -2 +4 2968 2969 -2 +4 14488 14489 -2 +4 39680 39681 -2 +4 @@ -45651,27 +46135,27 @@ 1 2 -51623 +100300 2 3 -37437 +72737 3 4 -21864 +42481 4 6 -10345 +20100 6 4208 -8510 +16535 @@ -45687,17 +46171,17 @@ 1 2 -98187 +190771 2 3 -28552 +55476 3 20 -3040 +5908 @@ -45798,19 +46282,19 @@ cil_attribute -168950 +328258 attributeid -168950 +328258 element -127933 +248565 constructor -1737 +3375 @@ -45824,7 +46308,7 @@ 1 2 -168950 +328258 @@ -45840,7 +46324,7 @@ 1 2 -168950 +328258 @@ -45856,17 +46340,17 @@ 1 2 -101559 +197322 2 3 -18883 +36690 3 92 -7490 +14553 @@ -45882,17 +46366,17 @@ 1 2 -109719 +213176 2 3 -15950 +30991 3 7 -2263 +4398 @@ -45908,57 +46392,57 @@ 1 2 -285 +555 2 3 -205 +399 3 4 -147 +287 4 5 -162 +316 5 8 -157 +306 8 11 -135 +263 11 19 -137 +267 19 33 -132 +258 33 64 -130 +253 64 179 -130 +253 187 15289 -110 +214 @@ -45974,57 +46458,57 @@ 1 2 -308 +599 2 3 -198 +384 3 4 -145 +282 4 5 -162 +316 5 7 -125 +243 7 10 -145 +282 10 17 -130 +253 17 31 -135 +263 31 50 -132 +258 50 151 -130 +253 152 15028 -122 +238 @@ -46034,19 +46518,19 @@ cil_attribute_named_argument -7973 +10939 attribute_id -4938 +7978 param -25 +155 value -128 +1095 @@ -46060,17 +46544,17 @@ 1 2 -1911 +5089 2 3 -3020 +2815 3 4 -7 +73 @@ -46086,17 +46570,17 @@ 1 2 -3839 +6560 2 3 -1095 +1402 3 4 -4 +14 @@ -46112,62 +46596,67 @@ 1 2 -3 +34 2 -3 -2 +4 +9 + + +4 +5 +9 5 -7 -2 +6 +14 7 -9 -2 +8 +4 -11 -14 -2 +8 +9 +14 + + +9 +11 +9 14 -19 -2 +30 +9 -19 -20 -1 +32 +43 +9 -22 -23 -2 +46 +47 +9 -26 -39 -2 +47 +48 +9 -55 -61 -2 +96 +308 +9 -347 -348 -2 - - -2859 -3660 -2 +725 +731 +9 @@ -46183,42 +46672,37 @@ 1 2 -8 +77 2 3 -5 +19 3 4 -2 +19 4 -6 -2 - - -6 -7 -1 - - -7 8 -2 +9 -9 -11 -2 +10 +14 +9 26 -39 -2 +45 +9 + + +47 +56 +9 @@ -46234,32 +46718,22 @@ 1 2 -71 +720 2 3 -25 +238 3 -4 -6 +5 +82 -4 -7 -11 - - -8 -301 -10 - - -347 -3871 -3 +5 +866 +53 @@ -46275,12 +46749,12 @@ 1 2 -120 +1066 2 -7 -8 +10 +29 @@ -46290,19 +46764,19 @@ cil_attribute_positional_argument -58735 +103139 attribute_id -57269 +97017 index -5 +29 value -4430 +17261 @@ -46316,12 +46790,12 @@ 1 2 -55901 +92336 2 -6 -1368 +7 +4680 @@ -46337,12 +46811,12 @@ 1 2 -55905 +92346 2 -5 -1364 +7 +4670 @@ -46356,29 +46830,34 @@ 12 -20 -21 -1 +14 +15 +4 -21 -22 -1 +24 +25 +4 -57 -58 -1 +117 +118 +4 -1368 -1369 -1 +141 +142 +4 -57269 -57270 -1 +961 +962 +4 + + +19919 +19920 +4 @@ -46392,24 +46871,29 @@ 12 -3 -4 -2 +4 +5 +4 5 6 -1 +9 -110 -111 -1 +25 +26 +4 -4331 -4332 -1 +433 +434 +4 + + +3150 +3151 +4 @@ -46425,27 +46909,22 @@ 1 2 -2894 +12298 2 3 -723 +2527 3 -4 -215 +6 +1446 -4 -9 -382 - - -9 -17524 -216 +6 +5556 +988 @@ -46461,12 +46940,12 @@ 1 2 -4414 +16935 2 6 -16 +326 @@ -46476,19 +46955,19 @@ metadata_handle -3178070 +6174756 entity -2925983 +5684969 location -1757 +3414 handle -141034 +274019 @@ -46502,17 +46981,17 @@ 1 2 -2683251 +5213358 2 3 -238091 +462594 3 638 -4640 +9015 @@ -46528,12 +47007,12 @@ 1 2 -2802586 +5445218 2 59 -123396 +239750 @@ -46549,72 +47028,72 @@ 1 3 -147 +287 3 36 -132 +258 36 79 -137 +267 79 130 -132 +258 130 200 -132 +258 200 288 -132 +258 288 400 -132 +258 403 527 -132 +258 528 744 -132 +258 747 1109 -135 +263 1116 1915 -132 +258 1920 4051 -132 +258 4053 50922 -132 +258 67370 92454 -7 +14 @@ -46630,67 +47109,67 @@ 1 2 -147 +287 3 20 -145 +282 20 46 -137 +267 46 76 -135 +263 77 119 -132 +258 119 176 -132 +258 176 253 -132 +258 255 332 -135 +263 338 481 -132 +258 483 683 -132 +258 685 1273 -132 +258 1295 2685 -132 +258 2710 55264 -125 +243 @@ -46706,62 +47185,62 @@ 1 2 -9741 +18927 2 3 -23163 +45004 3 5 -12303 +23904 5 6 -9009 +17504 6 7 -15504 +30124 7 9 -9761 +18966 9 11 -11363 +22078 11 13 -10822 +21026 13 21 -11042 +21454 21 39 -10869 +21118 39 83 -10583 +20563 83 1061 -6868 +13345 @@ -46777,52 +47256,52 @@ 1 2 -32363 +62879 2 3 -10852 +21084 3 4 -24173 +46967 4 5 -9741 +18927 5 6 -9979 +19389 6 7 -11350 +22054 7 11 -11982 +23281 11 19 -11315 +21985 19 41 -10729 +20846 41 702 -8545 +16603 From ef55ca179be065e052a6c8f7fd1c9f70044d5587 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Sat, 6 Feb 2021 21:13:55 +0100 Subject: [PATCH 227/429] Improve file read exception logging --- csharp/extractor/Semmle.Extraction/Entities/File.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction/Entities/File.cs b/csharp/extractor/Semmle.Extraction/Entities/File.cs index 4c339e49f7b..9ad618512a4 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/File.cs @@ -62,7 +62,7 @@ namespace Semmle.Extraction.Entities } catch (Exception exc) { - Context.ExtractionError($"Couldn't read file: {originalPath}", null, null, exc.StackTrace); + Context.ExtractionError($"Couldn't read file: {originalPath}. {exc.Message}", null, null, exc.StackTrace); } } From 2e30f2d9ceffcab4de4306ffa582402c11c30279 Mon Sep 17 00:00:00 2001 From: intrigus Date: Mon, 8 Feb 2021 00:05:02 +0100 Subject: [PATCH 228/429] Java: Fix QHelp & accept test output Accept test output for changed alert message. --- .../CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp | 8 +++++--- .../JxBrowserWithoutCertValidation.expected | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp index 27d10c15223..38b37901c0c 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp @@ -11,9 +11,11 @@ Versions smaller than 6.24 by default ignore any HTTPS certificate errors thereb

    Do either of these: -

  • Update to version 6.24 or 7.x.x as these correctly reject certificate errors by default.
  • -
  • Add a custom implementation of the LoadHandler interface whose onCertificateError method always returns true indicating that loading should be cancelled. -Then use the setLoadHandler method with your custom LoadHandler on every Browser you use.
  • +
      +
    • Update to version 6.24 or 7.x.x as these correctly reject certificate errors by default.
    • +
    • Add a custom implementation of the LoadHandler interface whose onCertificateError method always returns true indicating that loading should be cancelled. + Then use the setLoadHandler method with your custom LoadHandler on every Browser you use.
    • +

    diff --git a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected index 9b611b6cfc9..605aca10a26 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-295/jxbrowser-6.23.1/JxBrowserWithoutCertValidation.expected @@ -1 +1 @@ -| JxBrowserWithoutCertValidationV6_23_1.java:17:27:17:39 | new Browser(...) | This JxBrowser instance allows man-in-the-middle attacks. | +| JxBrowserWithoutCertValidationV6_23_1.java:17:27:17:39 | new Browser(...) | This JxBrowser instance may not check HTTPS certificates. | From 8ca75e41d2a500ce8835c80af932a9faa46d9c18 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 09:59:45 +0100 Subject: [PATCH 229/429] add change note --- javascript/change-notes/2021-02-08-immutable.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/change-notes/2021-02-08-immutable.md diff --git a/javascript/change-notes/2021-02-08-immutable.md b/javascript/change-notes/2021-02-08-immutable.md new file mode 100644 index 00000000000..8f4a11113e2 --- /dev/null +++ b/javascript/change-notes/2021-02-08-immutable.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* The dataflow libraries now model dataflow in the Immutable.js library. + Affected packages are + [Immutable.js](https://npmjs.com/package/immutable) From 504db8739d9b895e6fdb07760ca71d40db5ab68a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 10:00:26 +0100 Subject: [PATCH 230/429] fix typo in execa change-note file name --- .../change-notes/{202020-12-22-execa.md => 2020-12-22-execa.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename javascript/change-notes/{202020-12-22-execa.md => 2020-12-22-execa.md} (100%) diff --git a/javascript/change-notes/202020-12-22-execa.md b/javascript/change-notes/2020-12-22-execa.md similarity index 100% rename from javascript/change-notes/202020-12-22-execa.md rename to javascript/change-notes/2020-12-22-execa.md From bd50ed975f350749a1bb2fd65fdaf5a79f3b2274 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 8 Feb 2021 11:18:37 +0100 Subject: [PATCH 231/429] Fix doc comment --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 2846c3255ea..15199896390 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -588,7 +588,7 @@ class ForeachStmt extends LoopStmt, @foreach_stmt { /** Gets the called `MoveNext` or `MoveNextAsync` method. */ Method getMoveNext() { foreach_stmt_desugar(this, result, 3) } - /** Gets the called `Dispose` or `DisposeAsync` method. */ + /** Gets the called `Dispose` or `DisposeAsync` method, if any. */ Method getDispose() { foreach_stmt_desugar(this, result, 4) } /** Gets the called `Current` property. */ From 738d1bc3d46ac4e72e2ffc51dad9504b93094cca Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 8 Feb 2021 14:08:16 +0100 Subject: [PATCH 232/429] Python: More use of `API::Node` Co-authored-by: yoff --- python/ql/src/semmle/python/frameworks/Flask.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 3baa394ebcd..bfd1dac63ec 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -33,7 +33,7 @@ private module FlaskModel { API::Node request() { result = flask_attr("request") } /** Gets a reference to the `flask.make_response` function. */ - DataFlow::Node make_response() { result = flask_attr("make_response").getAUse() } + API::Node make_response() { result = flask_attr("make_response") } /** * Provides models for the `flask.Flask` class @@ -407,7 +407,7 @@ private module FlaskModel { override CallNode node; FlaskMakeResponseCall() { - node.getFunction() = flask::make_response().asCfgNode() + node.getFunction() = flask::make_response().getAUse().asCfgNode() or node.getFunction() = flask::Flask::make_response_().getAUse().asCfgNode() } From 2c4a477a4e2ba8eda5185feb2268154a7f5932a5 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 8 Feb 2021 14:08:34 +0100 Subject: [PATCH 233/429] Python: Support `moduleImport("dotted.name")` in API graphs --- python/ql/src/semmle/python/ApiGraphs.qll | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 3169592c8b2..7ad2a795c73 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -209,12 +209,14 @@ module API { /** * Gets a node corresponding to an import of module `m`. - * - * Note: You should only use this predicate for top level modules. If you want nodes corresponding to a submodule, - * you should use `.getMember` on the parent module. For example, for nodes corresponding to the module `foo.bar`, - * use `moduleImport("foo").getMember("bar")`. */ - Node moduleImport(string m) { result = Impl::MkModuleImport(m) } + Node moduleImport(string m) { + result = Impl::MkModuleImport(m) + or + exists(string before_dot, string after_dot | before_dot + "." + after_dot = m | + result = moduleImport(before_dot).getMember(after_dot) + ) + } /** * Provides the actual implementation of API graphs, cached for performance. From 46eb3fd10ac911f2a0c4244fefd9641cf75d6ff2 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 8 Feb 2021 14:22:42 +0100 Subject: [PATCH 234/429] Python: Even more `API::Node` pushing. --- python/ql/src/semmle/python/frameworks/Flask.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 51ef9b51d2f..1ac48689fd8 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -306,9 +306,9 @@ private module FlaskModel { private module FlaskRequestTracking { /** Gets a reference to either of the `get_json` or `get_data` attributes of a Flask request. */ - DataFlow::Node tainted_methods(string attr_name) { + API::Node tainted_methods(string attr_name) { attr_name in ["get_data", "get_json"] and - result = flask::request().getMember(attr_name).getAUse() + result = flask::request().getMember(attr_name) } } @@ -364,7 +364,7 @@ private module FlaskModel { ) or // methods (needs special handling to track bound-methods -- see `FlaskRequestMethodCallsAdditionalTaintStep` below) - this = FlaskRequestTracking::tainted_methods(attr_name) + this = FlaskRequestTracking::tainted_methods(attr_name).getAUse() } override string getSourceType() { result = "flask.request input" } @@ -374,7 +374,7 @@ private module FlaskModel { override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { // NOTE: `request -> request.tainted_method` part is handled as part of RequestInputAccess // tainted_method -> tainted_method() - nodeFrom = FlaskRequestTracking::tainted_methods(_) and + nodeFrom = FlaskRequestTracking::tainted_methods(_).getAUse() and nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode() } } @@ -443,7 +443,7 @@ private module FlaskModel { DataFlow::CfgNode { override CallNode node; - FlaskRedirectCall() { node.getFunction() = flask_attr("redirect").asCfgNode() } + FlaskRedirectCall() { node.getFunction() = flask_attr("redirect").getAUse().asCfgNode() } override DataFlow::Node getRedirectLocation() { result.asCfgNode() in [node.getArg(0), node.getArgByName("location")] From b278233a94bb4867633c47c5567eab155f056369 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 8 Feb 2021 15:44:29 +0000 Subject: [PATCH 235/429] JS: Mention all versions of Angular are supported --- docs/codeql/support/reusables/frameworks.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 4427407fe9d..40b4f2bdec7 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -93,7 +93,8 @@ JavaScript and TypeScript built-in support :widths: auto Name, Category - angularjs, HTML framework + angular (modern version), HTML framework + angular.js (legacy version), HTML framework axios, Network communicator browser, Runtime environment electron, Runtime environment From 72a699e0996d61cd92aec91fe659e42134c6401e Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 8 Feb 2021 16:55:18 +0100 Subject: [PATCH 236/429] Python: Add `CallCfgNode` class and rewrite using that class I prefer this name to `CfgCallNode` as the latter will make autocomplete more difficult. --- .../dataflow/new/internal/DataFlowPublic.qll | 23 ++++++-- .../ql/src/semmle/python/frameworks/Flask.qll | 53 +++++++------------ 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index 93540203f94..b86bdd2a3cf 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -165,6 +165,23 @@ class CfgNode extends Node, TCfgNode { override Location getLocation() { result = node.getLocation() } } +/** A data-flow node corresponding to a `CallNode` in the control-flow graph. */ +class CallCfgNode extends CfgNode { + override CallNode node; + + /** + * Gets the data-flow node for the function component of the call corresponding to this data-flow + * node. + */ + Node getFunction() { result.asCfgNode() = node.getFunction() } + + /** Gets the data-flow node corresponding to the nth argument of the call corresponding to this data-flow node */ + Node getArg(int i) { result.asCfgNode() = node.getArg(i) } + + /** Gets the data-flow node corresponding to the named argument of the call corresponding to this data-flow node */ + Node getArgByName(string name) { result.asCfgNode() = node.getArgByName(name) } +} + /** * An expression, viewed as a node in a data flow graph. * @@ -481,7 +498,7 @@ class LocalSourceNode extends Node { /** * Gets a call to this node. */ - Node getACall() { Cached::call(this, result) } + CallCfgNode getACall() { Cached::call(this, result) } } cached @@ -526,10 +543,10 @@ private module Cached { * Holds if `func` flows to the callee of `call`. */ cached - predicate call(LocalSourceNode func, Node call) { + predicate call(LocalSourceNode func, CallCfgNode call) { exists(CfgNode n | func.flowsTo(n) and - n.asCfgNode() = call.asCfgNode().(CallNode).getFunction() + n = call.getFunction() ) } } diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 1ac48689fd8..8b649a0d0ad 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -125,23 +125,21 @@ private module FlaskModel { abstract class InstanceSource extends HTTP::Server::HttpResponse::Range, DataFlow::Node { } /** A direct instantiation of `flask.Response`. */ - private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode { - override CallNode node; - + private class ClassInstantiation extends InstanceSource, DataFlow::CallCfgNode { ClassInstantiation() { this = classRef().getACall() } - override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) } + override DataFlow::Node getBody() { result = this.getArg(0) } override string getMimetypeDefault() { result = "text/html" } /** Gets the argument passed to the `mimetype` parameter, if any. */ private DataFlow::Node getMimetypeArg() { - result.asCfgNode() in [node.getArg(3), node.getArgByName("mimetype")] + result in [this.getArg(3), this.getArgByName("mimetype")] } /** Gets the argument passed to the `content_type` parameter, if any. */ private DataFlow::Node getContentTypeArg() { - result.asCfgNode() in [node.getArg(4), node.getArgByName("content_type")] + result in [this.getArg(4), this.getArgByName("content_type")] } override DataFlow::Node getMimetypeOrContentTypeArg() { @@ -228,13 +226,11 @@ private module FlaskModel { * * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.route */ - private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CfgNode { - override CallNode node; - - FlaskAppRouteCall() { node.getFunction() = flask::Flask::route().getAUse().asCfgNode() } + private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CallCfgNode { + FlaskAppRouteCall() { this.getFunction() = flask::Flask::route().getAUse() } override DataFlow::Node getUrlPatternArg() { - result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")] + result in [this.getArg(0), this.getArgByName("rule")] } override Function getARequestHandler() { result.getADecorator().getAFlowNode() = node } @@ -245,20 +241,14 @@ private module FlaskModel { * * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule */ - private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CfgNode { - override CallNode node; - - FlaskAppAddUrlRuleCall() { - node.getFunction() = flask::Flask::add_url_rule().getAUse().asCfgNode() - } + private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CallCfgNode { + FlaskAppAddUrlRuleCall() { this.getFunction() = flask::Flask::add_url_rule().getAUse() } override DataFlow::Node getUrlPatternArg() { - result.asCfgNode() in [node.getArg(0), node.getArgByName("rule")] + result in [this.getArg(0), this.getArgByName("rule")] } - DataFlow::Node getViewArg() { - result.asCfgNode() in [node.getArg(2), node.getArgByName("view_func")] - } + DataFlow::Node getViewArg() { result in [this.getArg(2), this.getArgByName("view_func")] } override Function getARequestHandler() { exists(DataFlow::LocalSourceNode func_src | @@ -375,7 +365,7 @@ private module FlaskModel { // NOTE: `request -> request.tainted_method` part is handled as part of RequestInputAccess // tainted_method -> tainted_method() nodeFrom = FlaskRequestTracking::tainted_methods(_).getAUse() and - nodeTo.asCfgNode().(CallNode).getFunction() = nodeFrom.asCfgNode() + nodeTo.(DataFlow::CallCfgNode).getFunction() = nodeFrom } } @@ -403,16 +393,15 @@ private module FlaskModel { * - https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.make_response * - https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response */ - private class FlaskMakeResponseCall extends HTTP::Server::HttpResponse::Range, DataFlow::CfgNode { - override CallNode node; - + private class FlaskMakeResponseCall extends HTTP::Server::HttpResponse::Range, + DataFlow::CallCfgNode { FlaskMakeResponseCall() { - node.getFunction() = flask::make_response().getAUse().asCfgNode() + this.getFunction() = flask::make_response().getAUse() or - node.getFunction() = flask::Flask::make_response_().getAUse().asCfgNode() + this.getFunction() = flask::Flask::make_response_().getAUse() } - override DataFlow::Node getBody() { result.asCfgNode() = node.getArg(0) } + override DataFlow::Node getBody() { result = this.getArg(0) } override string getMimetypeDefault() { result = "text/html" } @@ -440,13 +429,11 @@ private module FlaskModel { * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.redirect */ private class FlaskRedirectCall extends HTTP::Server::HttpRedirectResponse::Range, - DataFlow::CfgNode { - override CallNode node; - - FlaskRedirectCall() { node.getFunction() = flask_attr("redirect").getAUse().asCfgNode() } + DataFlow::CallCfgNode { + FlaskRedirectCall() { this.getFunction() = flask_attr("redirect").getAUse() } override DataFlow::Node getRedirectLocation() { - result.asCfgNode() in [node.getArg(0), node.getArgByName("location")] + result in [this.getArg(0), this.getArgByName("location")] } override DataFlow::Node getBody() { none() } From c59b5c98cb661dd450cd2c78489df6a201738373 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 8 Feb 2021 19:14:11 +0100 Subject: [PATCH 237/429] Python: Replace use of `AttrNode` with `getMember` --- .../ql/src/semmle/python/frameworks/Flask.qll | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index 8b649a0d0ad..c0702ab7391 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -312,46 +312,42 @@ private module FlaskModel { RequestInputAccess() { // attributes - exists(AttrNode attr | - this.asCfgNode() = attr and - attr.getObject(attr_name) = flask::request().getAUse().asCfgNode() - | - attr_name in [ - // str - "path", "full_path", "base_url", "url", "access_control_request_method", - "content_encoding", "content_md5", "content_type", "data", "method", "mimetype", - "origin", "query_string", "referrer", "remote_addr", "remote_user", "user_agent", - // dict - "environ", "cookies", "mimetype_params", "view_args", - // json - "json", - // List[str] - "access_route", - // file-like - "stream", "input_stream", - // MultiDict[str, str] - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict - "args", "values", "form", - // MultiDict[str, FileStorage] - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage - // TODO: FileStorage needs extra taint steps - "files", - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.HeaderSet - "access_control_request_headers", "pragma", - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Accept - // TODO: Kinda badly modeled for now -- has type List[Tuple[value, quality]], and some extra methods - "accept_charsets", "accept_encodings", "accept_languages", "accept_mimetypes", - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Authorization - // TODO: dict subclass with extra attributes like `username` and `password` - "authorization", - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.RequestCacheControl - // TODO: has attributes like `no_cache`, and `to_header` method (actually, many of these models do) - "cache_control", - // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers - // TODO: dict-like with wsgiref.headers.Header compatibility methods - "headers" - ] - ) + this = flask::request().getMember(attr_name).getAUse() and + attr_name in [ + // str + "path", "full_path", "base_url", "url", "access_control_request_method", + "content_encoding", "content_md5", "content_type", "data", "method", "mimetype", "origin", + "query_string", "referrer", "remote_addr", "remote_user", "user_agent", + // dict + "environ", "cookies", "mimetype_params", "view_args", + // json + "json", + // List[str] + "access_route", + // file-like + "stream", "input_stream", + // MultiDict[str, str] + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict + "args", "values", "form", + // MultiDict[str, FileStorage] + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage + // TODO: FileStorage needs extra taint steps + "files", + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.HeaderSet + "access_control_request_headers", "pragma", + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Accept + // TODO: Kinda badly modeled for now -- has type List[Tuple[value, quality]], and some extra methods + "accept_charsets", "accept_encodings", "accept_languages", "accept_mimetypes", + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Authorization + // TODO: dict subclass with extra attributes like `username` and `password` + "authorization", + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.RequestCacheControl + // TODO: has attributes like `no_cache`, and `to_header` method (actually, many of these models do) + "cache_control", + // https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers + // TODO: dict-like with wsgiref.headers.Header compatibility methods + "headers" + ] or // methods (needs special handling to track bound-methods -- see `FlaskRequestMethodCallsAdditionalTaintStep` below) this = FlaskRequestTracking::tainted_methods(attr_name).getAUse() From 7583904046bebf3ae2d9c44dde34b1b01a6d8f6f Mon Sep 17 00:00:00 2001 From: Alexander Eyers-Taylor Date: Mon, 8 Feb 2021 18:54:13 +0000 Subject: [PATCH 238/429] Update the language specification to allow empty var_decls This is a degenerate form that is accepted in the compiler even if they don't make much sense. Fixes #5060 --- .../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 df1da36a1ba..0fe54210504 100644 --- a/docs/codeql/ql-language-reference/ql-language-specification.rst +++ b/docs/codeql/ql-language-reference/ql-language-specification.rst @@ -374,7 +374,7 @@ A *variable declaration list* provides a sequence of variables and a type for ea :: - var_decls ::= var_decl ("," var_decl)* + var_decls ::= (var_decl ("," var_decl)*)? var_decl ::= type simpleId A valid variable declaration list must not include two declarations with the same variable name. Moreover, if the declaration has a typing environment that applies, it must not use a variable name that is already present in that typing environment. @@ -820,7 +820,7 @@ The head of the predicate gives a name, an optional *result type*, and a sequenc :: - head ::= ("predicate" | type) predicateName "(" (var_decls)? ")" + head ::= ("predicate" | type) predicateName "(" var_decls ")" The body of a predicate is of one of three forms: @@ -1209,7 +1209,7 @@ An aggregation can be written in one of two forms: :: - aggregation ::= aggid ("[" expr "]")? "(" (var_decls)? ("|" (formula)? ("|" as_exprs ("order" "by" aggorderbys)?)?)? ")" + aggregation ::= aggid ("[" expr "]")? "(" var_decls ("|" (formula)? ("|" as_exprs ("order" "by" aggorderbys)?)?)? ")" | aggid ("[" expr "]")? "(" as_exprs ("order" "by" aggorderbys)? ")" | "unique" "(" var_decls "|" (formula)? ("|" as_exprs)? ")" @@ -2046,7 +2046,7 @@ The complete grammar for QL is as follows: | "language" "[" "monotonicAggregates" "]" | "bindingset" "[" (variable ( "," variable)*)? "]" - head ::= ("predicate" | type) predicateName "(" (var_decls)? ")" + head ::= ("predicate" | type) predicateName "(" var_decls ")" optbody ::= ";" | "{" formula "}" @@ -2070,7 +2070,7 @@ The complete grammar for QL is as follows: | qldoc? annotations "class" classname "=" type ";" | qldoc? annotations "module" modulename "=" moduleId ";" - var_decls ::= var_decl ("," var_decl)* + var_decls ::= (var_decl ("," var_decl)*)? var_decl ::= type simpleId @@ -2157,7 +2157,7 @@ The complete grammar for QL is as follows: postfix_cast ::= primary "." "(" type ")" - aggregation ::= aggid ("[" expr "]")? "(" (var_decls)? ("|" (formula)? ("|" as_exprs ("order" "by" aggorderbys)?)?)? ")" + aggregation ::= aggid ("[" expr "]")? "(" var_decls ("|" (formula)? ("|" as_exprs ("order" "by" aggorderbys)?)?)? ")" | aggid ("[" expr "]")? "(" as_exprs ("order" "by" aggorderbys)? ")" | "unique" "(" var_decls "|" (formula)? ("|" as_exprs)? ")" From cb16c64540134199475dc3093fb3e260ecfe8283 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 19:41:25 +0000 Subject: [PATCH 239/429] Call out the issue of copied code for C/C++ example code in the C/C++ CodeQL Tests README.md (where we talk about it for tests). --- cpp/ql/test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/README.md b/cpp/ql/test/README.md index 417d7bbe19d..6cf9082eaea 100644 --- a/cpp/ql/test/README.md +++ b/cpp/ql/test/README.md @@ -1,6 +1,6 @@ # C/C++ CodeQL tests -This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. See [Contributing to CodeQL](/CONTRIBUTING.md) for general information about contributing to this repository. +This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. The principles under 'Copying code' also apply to any other C/C++ code in this repository, such as examples linked from query `.qhelp` files in `cp/ql/src`. See [Contributing to CodeQL](/CONTRIBUTING.md) for more general information about contributing to this repository. The tests can be run through Visual Studio Code. Advanced users may also use the `codeql test run` command. From 74178a5e8627ea151df80a6d9af50642657ec222 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 19:55:02 +0000 Subject: [PATCH 240/429] Call out the copied code issue for qhelp files again (more generally) in the Supported CodeQL queries and libraries doc. --- docs/supported-queries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/supported-queries.md b/docs/supported-queries.md index dc02a1e547c..0c4b7069f5d 100644 --- a/docs/supported-queries.md +++ b/docs/supported-queries.md @@ -20,7 +20,7 @@ The process must begin with the first step and must conclude with the final step Query help files explain the purpose of your query to other users. Write your query help in a `.qhelp` file and save it in the same directory as your query. For more information on writing query help, see the [Query help style guide](query-help-style-guide.md). - - Note, in particular, that almost all queries need to have a pair of "before" and "after" examples demonstrating the kind of problem the query identifies and how to fix it. Make sure that the examples are actually consistent with what the query does, for example by including them in your unit tests. + - Note, in particular, that almost all queries need to have a pair of "before" and "after" examples demonstrating the kind of problem the query identifies and how to fix it. Make sure that the examples are actually consistent with what the query does, for example by including them in your unit tests. Examples must be original, not copied from third-party sources. - At the time of writing, there is no way of previewing help locally. Once you've opened a PR, a preview will be created as part of the CI checks. A GitHub employee will review this and let you know of any problems. 3. **Write unit tests** From 690b525192b682f7bbf2f035c42fc6701fdbf2d0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 19:52:01 +0000 Subject: [PATCH 241/429] Add a link to the C/C++ CodeQL Tests README.md from the Supported CodeQL queries and libraries doc. --- docs/supported-queries.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/supported-queries.md b/docs/supported-queries.md index 0c4b7069f5d..5facba235e9 100644 --- a/docs/supported-queries.md +++ b/docs/supported-queries.md @@ -27,7 +27,8 @@ The process must begin with the first step and must conclude with the final step Add one or more unit tests for the query (and for any library changes you make) to the `ql//ql/test/experimental` directory. Tests for library changes go into the `library-tests` subdirectory, and tests for queries go into `query-tests` with their relative path mirroring the query's location under `ql//ql/src/experimental`. - See the section on [Testing custom queries](https://help.semmle.com/codeql/codeql-cli/procedures/test-queries.html) in the [CodeQL documentation](https://help.semmle.com/codeql/) for more information. + - see the section on [Testing custom queries](https://help.semmle.com/codeql/codeql-cli/procedures/test-queries.html) in the [CodeQL documentation](https://help.semmle.com/codeql/) for more information. + - see [C/C++ CodeQL tests](/cpp/ql/test/README.md) for more information about contributing tests for C/C++ queries in particular. 4. **Test for correctness on real-world code** From 65ea1a4631366beb8273aa5a76a64f48d65fce51 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 19:39:14 +0000 Subject: [PATCH 242/429] Add hints / links about tests and documentation to CONTRIBUTING.md. --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 39552ad0bd9..69247da373c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,11 @@ Experimental queries and libraries may not be actively maintained as the [suppor After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md). +6. **Query Help Files and Unit Tests** + + - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. + - see [Supported CodeQL queries and libraries](docs/supported-queries.md) for more information about contributing query help files and unit tests. + ## Using your personal data If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. From e1ca762bbc9958539a3b4fec63875fb25a9491b7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:24:15 +0000 Subject: [PATCH 243/429] Fix layout. --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 69247da373c..8366d80ce2b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,15 +49,15 @@ If you have an idea for a query that you would like to share with other CodeQL u - The query must have at least one true positive result on some revision of a real project. -Experimental queries and libraries may not be actively maintained as the [supported](docs/supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. - -After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md). - 6. **Query Help Files and Unit Tests** - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. - see [Supported CodeQL queries and libraries](docs/supported-queries.md) for more information about contributing query help files and unit tests. +Experimental queries and libraries may not be actively maintained as the [supported](docs/supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. + +After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md). + ## Using your personal data If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product. From bd255617d8d0592852519b397fd8882504d065ae Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:25:35 +0000 Subject: [PATCH 244/429] Three copies of a link is too much. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8366d80ce2b..6e417a0d9c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,7 +54,7 @@ If you have an idea for a query that you would like to share with other CodeQL u - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. - see [Supported CodeQL queries and libraries](docs/supported-queries.md) for more information about contributing query help files and unit tests. -Experimental queries and libraries may not be actively maintained as the [supported](docs/supported-queries.md) libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. +Experimental queries and libraries may not be actively maintained as the supported libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. After the experimental query is merged, we welcome pull requests to improve it. Before a query can be moved out of the `experimental` subdirectory, it must satisfy [the requirements for being a supported query](docs/supported-queries.md). From 07b263bb2fb6f184eca09995ac9df78fa9948259 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:27:28 +0000 Subject: [PATCH 245/429] Typo. --- cpp/ql/test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/README.md b/cpp/ql/test/README.md index 6cf9082eaea..efa020a074f 100644 --- a/cpp/ql/test/README.md +++ b/cpp/ql/test/README.md @@ -1,6 +1,6 @@ # C/C++ CodeQL tests -This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. The principles under 'Copying code' also apply to any other C/C++ code in this repository, such as examples linked from query `.qhelp` files in `cp/ql/src`. See [Contributing to CodeQL](/CONTRIBUTING.md) for more general information about contributing to this repository. +This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. The principles under 'Copying code' also apply to any other C/C++ code in this repository, such as examples linked from query `.qhelp` files in `cpp/ql/src`. See [Contributing to CodeQL](/CONTRIBUTING.md) for more general information about contributing to this repository. The tests can be run through Visual Studio Code. Advanced users may also use the `codeql test run` command. From 8bf9fc611168e63303b84de5216428fa3025a679 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 8 Feb 2021 20:29:46 +0000 Subject: [PATCH 246/429] Consistent capitalisation. --- docs/supported-queries.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/supported-queries.md b/docs/supported-queries.md index 5facba235e9..55530c2fa12 100644 --- a/docs/supported-queries.md +++ b/docs/supported-queries.md @@ -27,8 +27,8 @@ The process must begin with the first step and must conclude with the final step Add one or more unit tests for the query (and for any library changes you make) to the `ql//ql/test/experimental` directory. Tests for library changes go into the `library-tests` subdirectory, and tests for queries go into `query-tests` with their relative path mirroring the query's location under `ql//ql/src/experimental`. - - see the section on [Testing custom queries](https://help.semmle.com/codeql/codeql-cli/procedures/test-queries.html) in the [CodeQL documentation](https://help.semmle.com/codeql/) for more information. - - see [C/C++ CodeQL tests](/cpp/ql/test/README.md) for more information about contributing tests for C/C++ queries in particular. + - See the section on [Testing custom queries](https://help.semmle.com/codeql/codeql-cli/procedures/test-queries.html) in the [CodeQL documentation](https://help.semmle.com/codeql/) for more information. + - See [C/C++ CodeQL tests](/cpp/ql/test/README.md) for more information about contributing tests for C/C++ queries in particular. 4. **Test for correctness on real-world code** From f114ef1f06e6965023143f9385cd32e6f49a76cc Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Mon, 8 Feb 2021 16:57:49 -0800 Subject: [PATCH 247/429] Adding unit tests --- .../DangerousNativeFunctionCall.expected | 1 + .../DangerousNativeFunctionCall.qlref | 1 + .../backdoor/PotentialTimeBomb.expected | 23 ++ .../backdoor/PotentialTimeBomb.qlref | 1 + .../ProcessNameToHashTaintFlow.expected | 3 + .../backdoor/ProcessNameToHashTaintFlow.qlref | 1 + .../Security Features/backdoor/test.cs | 76 +++++ .../ModifiedFnvFunctionDetection.expected | 1 + .../ModifiedFnvFunctionDetection.qlref | 1 + ...mberOfKnownCommandsAboveThreshold.expected | 1 + .../NumberOfKnownCommandsAboveThreshold.qlref | 1 + ...NumberOfKnownHashesAboveThreshold.expected | 248 ++++++++++++++ .../NumberOfKnownHashesAboveThreshold.qlref | 1 + ...mberOfKnownLiteralsAboveThreshold.expected | 140 ++++++++ .../NumberOfKnownLiteralsAboveThreshold.qlref | 1 + ...rOfKnownMethodNamesAboveThreshold.expected | 104 ++++++ ...mberOfKnownMethodNamesAboveThreshold.qlref | 1 + ...SwallowEverythingExceptionHandler.expected | 3 + .../SwallowEverythingExceptionHandler.qlref | 1 + .../campaign/Solorigate/test.cs | 309 ++++++++++++++++++ 20 files changed, 918 insertions(+) create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.expected create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlref create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.expected create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.qlref create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.expected create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlref create mode 100644 csharp/ql/test/experimental/Security Features/backdoor/test.cs create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qlref create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qlref create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qlref create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qlref create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qlref create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qlref create mode 100644 csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs diff --git a/csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.expected b/csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.expected new file mode 100644 index 00000000000..f890a844778 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.expected @@ -0,0 +1 @@ +| test.cs:31:9:31:74 | call to method InitiateSystemShutdownExW | Call to an external method 'InitiateSystemShutdownExW'. | diff --git a/csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlref b/csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlref new file mode 100644 index 00000000000..1215c001b40 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/DangerousNativeFunctionCall.qlref @@ -0,0 +1 @@ +experimental/Security Features/backdoor/DangerousNativeFunctionCall.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.expected b/csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.expected new file mode 100644 index 00000000000..490a71b0c0c --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.expected @@ -0,0 +1,23 @@ +edges +| test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:36:70:48 | access to local variable lastWriteTime | +| test.cs:70:13:70:71 | call to method CompareTo : Int32 | test.cs:70:13:70:76 | ... >= ... | +| test.cs:70:36:70:48 | access to local variable lastWriteTime | test.cs:70:36:70:70 | call to method AddHours | +| test.cs:70:36:70:48 | access to local variable lastWriteTime | test.cs:70:36:70:70 | call to method AddHours : DateTime | +| test.cs:70:36:70:48 | access to local variable lastWriteTime : DateTime | test.cs:70:36:70:70 | call to method AddHours | +| test.cs:70:36:70:48 | access to local variable lastWriteTime : DateTime | test.cs:70:36:70:70 | call to method AddHours : DateTime | +| test.cs:70:36:70:70 | call to method AddHours | test.cs:70:13:70:71 | call to method CompareTo | +| test.cs:70:36:70:70 | call to method AddHours | test.cs:70:13:70:71 | call to method CompareTo : Int32 | +| test.cs:70:36:70:70 | call to method AddHours : DateTime | test.cs:70:13:70:71 | call to method CompareTo | +| test.cs:70:36:70:70 | call to method AddHours : DateTime | test.cs:70:13:70:71 | call to method CompareTo : Int32 | +#select +| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:71 | call to method CompareTo | Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | an offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | +| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:71 | call to method CompareTo : Int32 | Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | an offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | +| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:76 | ... >= ... | Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | an offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | +| test.cs:70:9:73:9 | if (...) ... | test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | test.cs:70:13:70:76 | ... >= ... : Boolean | Possible TimeBomb logic triggered by $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:70:13:70:71 | call to method CompareTo | call to method CompareTo | test.cs:70:36:70:70 | call to method AddHours | an offset | test.cs:68:34:68:76 | call to method GetLastWriteTime | last modification time of a file | +nodes +| test.cs:68:34:68:76 | call to method GetLastWriteTime : DateTime | semmle.label | call to method GetLastWriteTime : DateTime | +| test.cs:70:13:70:71 | call to method CompareTo | semmle.label | call to method CompareTo | +| test.cs:70:13:70:71 | call to method CompareTo : Int32 | semmle.label | call to method CompareTo : Int32 | +| test.cs:70:13:70:76 | ... >= ... | semmle.label | ... >= ... | +| test.cs:70:36:70:48 | access to local variable lastWriteTime | semmle.label | access to local variable lastWriteTime | +| test.cs:70:36:70:70 | call to method AddHours | semmle.label | call to method AddHours | diff --git a/csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.qlref b/csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.qlref new file mode 100644 index 00000000000..f76817aa089 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.qlref @@ -0,0 +1 @@ +experimental/Security Features/backdoor/PotentialTimeBomb.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.expected b/csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.expected new file mode 100644 index 00000000000..58e3dda0964 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.expected @@ -0,0 +1,3 @@ +edges +nodes +#select diff --git a/csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlref b/csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlref new file mode 100644 index 00000000000..d1d0d520d61 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.qlref @@ -0,0 +1 @@ +experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/backdoor/test.cs b/csharp/ql/test/experimental/Security Features/backdoor/test.cs new file mode 100644 index 00000000000..aea05818423 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/backdoor/test.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace System.IO +{ + public class File + { + public static DateTime GetLastWriteTime(string s) + { + return new DateTime(DateTime.MaxValue.Ticks); + } + } +} + +namespace System.Diagnostics +{ + public class Process + { + public static string GetCurrentProcess() { return "test"; } + } +} + +class External { + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool InitiateSystemShutdownExW([In] string lpMachineName, [In] string lpMessage, [In] uint dwTimeout, [MarshalAs(UnmanagedType.Bool)][In] bool bForceAppsClosed, [MarshalAs(UnmanagedType.Bool)][In] bool bRebootAfterShutdown, [In] uint dwReason); + + void TestDangerousNativeFunctionCall() + { + InitiateSystemShutdownExW(null, null, 0U, true, true, 2147745794U); // BUG : DangerousNativeFunctionCall + } + + ulong GetFvnHash(string s) + { + ulong num = 14695981039346656037UL; /* FNV base offset */ + try + { + foreach (byte b in Encoding.UTF8.GetBytes(s)) + { + num ^= (ulong)b; + num *= 1099511628211UL; /* FNV prime */ + } + } + catch + { + } + // regular FVN + return num; + } + + void IndirectTestProcessNameToHashTaintFlow( string s) + { + GetFvnHash(s); // BUG : ProcessNameToHashTaintFlow + } + + void TestProcessNameToHashTaintFlow() + { + GetFvnHash( System.Diagnostics.Process.GetCurrentProcess() ); // BUG : ProcessNameToHashTaintFlow + + string proc = System.Diagnostics.Process.GetCurrentProcess(); + + IndirectTestProcessNameToHashTaintFlow( proc ); + } + + void TestTimeBomb() + { + DateTime lastWriteTime = System.IO.File.GetLastWriteTime("someFile"); + int num = new Random().Next(288, 336); + if (DateTime.Now.CompareTo(lastWriteTime.AddHours((double)num)) >= 0) // BUG : Potential time bomb + { + // Some code here + } + } + +} \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected new file mode 100644 index 00000000000..da578042bc3 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.expected @@ -0,0 +1 @@ +| test.cs:40:16:40:36 | 6605813339339102567 | The variable $@ seems to be used as part of a FNV-like hash calculation, that is modified by an additional $@ expression using literal $@. | test.cs:26:9:26:11 | num | num | test.cs:40:10:40:36 | ... ^ ... | xor | test.cs:40:16:40:36 | 6605813339339102567 | 6605813339339102567 | diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qlref b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qlref new file mode 100644 index 00000000000..af0428b3391 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qlref @@ -0,0 +1 @@ +experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected new file mode 100644 index 00000000000..fa8afc54079 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.expected @@ -0,0 +1 @@ +| test.cs:43:7:43:15 | JobEngine | The enum $@ may be related to Solorigate. It matches 19 of the values used for commands in the enum. | test.cs:43:7:43:15 | JobEngine | JobEngine | diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qlref b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qlref new file mode 100644 index 00000000000..11d2fef0441 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qlref @@ -0,0 +1 @@ +experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected new file mode 100644 index 00000000000..3603cf8a20a --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.expected @@ -0,0 +1,248 @@ +| test.cs:10:15:10:36 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:10:15:10:36 | 14695981039346656037 | 14695981039346656037 | +| test.cs:15:11:15:25 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:15:11:15:25 | 1099511628211 | 1099511628211 | +| test.cs:26:15:26:36 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:26:15:26:36 | 14695981039346656037 | 14695981039346656037 | +| test.cs:32:12:32:26 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:32:12:32:26 | 1099511628211 | 1099511628211 | +| test.cs:40:16:40:36 | 6605813339339102567 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:40:16:40:36 | 6605813339339102567 | 6605813339339102567 | +| test.cs:173:5:173:24 | 10063651499895178962 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:5:173:24 | 10063651499895178962 | 10063651499895178962 | +| test.cs:173:27:173:46 | 10235971842993272939 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:27:173:46 | 10235971842993272939 | 10235971842993272939 | +| test.cs:173:49:173:68 | 10296494671777307979 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:173:49:173:68 | 10296494671777307979 | 10296494671777307979 | +| test.cs:174:5:174:24 | 10336842116636872171 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:5:174:24 | 10336842116636872171 | 10336842116636872171 | +| test.cs:174:27:174:46 | 10374841591685794123 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:27:174:46 | 10374841591685794123 | 10374841591685794123 | +| test.cs:174:49:174:68 | 10393903804869831898 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:174:49:174:68 | 10393903804869831898 | 10393903804869831898 | +| test.cs:175:5:175:24 | 10463926208560207521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:5:175:24 | 10463926208560207521 | 10463926208560207521 | +| test.cs:175:27:175:46 | 10484659978517092504 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:27:175:46 | 10484659978517092504 | 10484659978517092504 | +| test.cs:175:49:175:68 | 10501212300031893463 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:175:49:175:68 | 10501212300031893463 | 10501212300031893463 | +| test.cs:176:5:176:24 | 10545868833523019926 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:5:176:24 | 10545868833523019926 | 10545868833523019926 | +| test.cs:176:27:176:46 | 10657751674541025650 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:27:176:46 | 10657751674541025650 | 10657751674541025650 | +| test.cs:176:49:176:66 | 106672141413120087 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:49:176:66 | 106672141413120087 | 106672141413120087 | +| test.cs:176:69:176:88 | 10734127004244879770 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:176:69:176:88 | 10734127004244879770 | 10734127004244879770 | +| test.cs:177:5:177:24 | 10829648878147112121 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:5:177:24 | 10829648878147112121 | 10829648878147112121 | +| test.cs:177:27:177:39 | 1099511628211 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:27:177:39 | 1099511628211 | 1099511628211 | +| test.cs:177:42:177:61 | 11073283311104541690 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:42:177:61 | 11073283311104541690 | 11073283311104541690 | +| test.cs:177:64:177:82 | 1109067043404435916 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:177:64:177:82 | 1109067043404435916 | 1109067043404435916 | +| test.cs:178:5:178:24 | 11109294216876344399 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:5:178:24 | 11109294216876344399 | 11109294216876344399 | +| test.cs:178:27:178:46 | 11266044540366291518 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:27:178:46 | 11266044540366291518 | 11266044540366291518 | +| test.cs:178:49:178:68 | 11385275378891906608 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:178:49:178:68 | 11385275378891906608 | 11385275378891906608 | +| test.cs:179:5:179:24 | 11771945869106552231 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:5:179:24 | 11771945869106552231 | 11771945869106552231 | +| test.cs:179:27:179:46 | 11801746708619571308 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:27:179:46 | 11801746708619571308 | 11801746708619571308 | +| test.cs:179:49:179:68 | 11818825521849580123 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:179:49:179:68 | 11818825521849580123 | 11818825521849580123 | +| test.cs:180:5:180:24 | 11913842725949116895 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:5:180:24 | 11913842725949116895 | 11913842725949116895 | +| test.cs:180:27:180:46 | 12027963942392743532 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:27:180:46 | 12027963942392743532 | 12027963942392743532 | +| test.cs:180:49:180:68 | 12094027092655598256 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:180:49:180:68 | 12094027092655598256 | 12094027092655598256 | +| test.cs:181:5:181:24 | 12343334044036541897 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:5:181:24 | 12343334044036541897 | 12343334044036541897 | +| test.cs:181:27:181:46 | 12445177985737237804 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:27:181:46 | 12445177985737237804 | 12445177985737237804 | +| test.cs:181:49:181:68 | 12445232961318634374 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:181:49:181:68 | 12445232961318634374 | 12445232961318634374 | +| test.cs:182:5:182:24 | 12574535824074203265 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:5:182:24 | 12574535824074203265 | 12574535824074203265 | +| test.cs:182:27:182:46 | 12679195163651834776 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:27:182:46 | 12679195163651834776 | 12679195163651834776 | +| test.cs:182:49:182:68 | 12709986806548166638 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:182:49:182:68 | 12709986806548166638 | 12709986806548166638 | +| test.cs:183:5:183:24 | 12718416789200275332 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:5:183:24 | 12718416789200275332 | 12718416789200275332 | +| test.cs:183:27:183:46 | 12785322942775634499 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:27:183:46 | 12785322942775634499 | 12785322942775634499 | +| test.cs:183:49:183:68 | 12790084614253405985 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:183:49:183:68 | 12790084614253405985 | 12790084614253405985 | +| test.cs:184:5:184:24 | 12969190449276002545 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:5:184:24 | 12969190449276002545 | 12969190449276002545 | +| test.cs:184:27:184:46 | 13014156621614176974 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:27:184:46 | 13014156621614176974 | 13014156621614176974 | +| test.cs:184:49:184:68 | 13029357933491444455 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:184:49:184:68 | 13029357933491444455 | 13029357933491444455 | +| test.cs:185:5:185:24 | 13135068273077306806 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:5:185:24 | 13135068273077306806 | 13135068273077306806 | +| test.cs:185:27:185:46 | 13260224381505715848 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:27:185:46 | 13260224381505715848 | 13260224381505715848 | +| test.cs:185:49:185:68 | 13316211011159594063 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:185:49:185:68 | 13316211011159594063 | 13316211011159594063 | +| test.cs:186:5:186:24 | 13464308873961738403 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:5:186:24 | 13464308873961738403 | 13464308873961738403 | +| test.cs:186:27:186:46 | 13544031715334011032 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:27:186:46 | 13544031715334011032 | 13544031715334011032 | +| test.cs:186:49:186:68 | 13581776705111912829 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:186:49:186:68 | 13581776705111912829 | 13581776705111912829 | +| test.cs:187:5:187:24 | 13599785766252827703 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:5:187:24 | 13599785766252827703 | 13599785766252827703 | +| test.cs:187:27:187:46 | 13611051401579634621 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:27:187:46 | 13611051401579634621 | 13611051401579634621 | +| test.cs:187:49:187:68 | 13611814135072561278 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:187:49:187:68 | 13611814135072561278 | 13611814135072561278 | +| test.cs:188:5:188:24 | 13655261125244647696 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:5:188:24 | 13655261125244647696 | 13655261125244647696 | +| test.cs:188:27:188:45 | 1367627386496056834 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:27:188:45 | 1367627386496056834 | 1367627386496056834 | +| test.cs:188:48:188:66 | 1368907909245890092 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:48:188:66 | 1368907909245890092 | 1368907909245890092 | +| test.cs:188:69:188:88 | 13693525876560827283 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:188:69:188:88 | 13693525876560827283 | 13693525876560827283 | +| test.cs:189:5:189:24 | 13783346438774742614 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:5:189:24 | 13783346438774742614 | 13783346438774742614 | +| test.cs:189:27:189:46 | 13799353263187722717 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:27:189:46 | 13799353263187722717 | 13799353263187722717 | +| test.cs:189:49:189:68 | 13825071784440082496 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:189:49:189:68 | 13825071784440082496 | 13825071784440082496 | +| test.cs:190:5:190:24 | 13852439084267373191 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:5:190:24 | 13852439084267373191 | 13852439084267373191 | +| test.cs:190:27:190:46 | 13876356431472225791 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:27:190:46 | 13876356431472225791 | 13876356431472225791 | +| test.cs:190:49:190:68 | 14055243717250701608 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:190:49:190:68 | 14055243717250701608 | 14055243717250701608 | +| test.cs:191:5:191:24 | 14079676299181301772 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:5:191:24 | 14079676299181301772 | 14079676299181301772 | +| test.cs:191:27:191:46 | 14095938998438966337 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:27:191:46 | 14095938998438966337 | 14095938998438966337 | +| test.cs:191:49:191:68 | 14111374107076822891 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:191:49:191:68 | 14111374107076822891 | 14111374107076822891 | +| test.cs:192:5:192:24 | 14193859431895170587 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:5:192:24 | 14193859431895170587 | 14193859431895170587 | +| test.cs:192:27:192:46 | 14226582801651130532 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:27:192:46 | 14226582801651130532 | 14226582801651130532 | +| test.cs:192:49:192:68 | 14243671177281069512 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:192:49:192:68 | 14243671177281069512 | 14243671177281069512 | +| test.cs:193:5:193:24 | 14256853800858727521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:5:193:24 | 14256853800858727521 | 14256853800858727521 | +| test.cs:193:27:193:46 | 14480775929210717493 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:27:193:46 | 14480775929210717493 | 14480775929210717493 | +| test.cs:193:49:193:68 | 14482658293117931546 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:193:49:193:68 | 14482658293117931546 | 14482658293117931546 | +| test.cs:194:5:194:24 | 14513577387099045298 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:5:194:24 | 14513577387099045298 | 14513577387099045298 | +| test.cs:194:27:194:46 | 14630721578341374856 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:27:194:46 | 14630721578341374856 | 14630721578341374856 | +| test.cs:194:49:194:68 | 14695981039346656037 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:194:49:194:68 | 14695981039346656037 | 14695981039346656037 | +| test.cs:195:5:195:24 | 14710585101020280896 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:5:195:24 | 14710585101020280896 | 14710585101020280896 | +| test.cs:195:27:195:45 | 1475579823244607677 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:27:195:45 | 1475579823244607677 | 1475579823244607677 | +| test.cs:195:48:195:67 | 14868920869169964081 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:48:195:67 | 14868920869169964081 | 14868920869169964081 | +| test.cs:195:70:195:89 | 14968320160131875803 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:195:70:195:89 | 14968320160131875803 | 14968320160131875803 | +| test.cs:196:5:196:24 | 14971809093655817917 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:5:196:24 | 14971809093655817917 | 14971809093655817917 | +| test.cs:196:27:196:46 | 15039834196857999838 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:27:196:46 | 15039834196857999838 | 15039834196857999838 | +| test.cs:196:49:196:68 | 15092207615430402812 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:196:49:196:68 | 15092207615430402812 | 15092207615430402812 | +| test.cs:197:5:197:24 | 15114163911481793350 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:5:197:24 | 15114163911481793350 | 15114163911481793350 | +| test.cs:197:27:197:46 | 15194901817027173566 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:27:197:46 | 15194901817027173566 | 15194901817027173566 | +| test.cs:197:49:197:68 | 15267980678929160412 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:197:49:197:68 | 15267980678929160412 | 15267980678929160412 | +| test.cs:198:5:198:24 | 15457732070353984570 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:5:198:24 | 15457732070353984570 | 15457732070353984570 | +| test.cs:198:27:198:46 | 15514036435533858158 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:27:198:46 | 15514036435533858158 | 15514036435533858158 | +| test.cs:198:49:198:68 | 15535773470978271326 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:198:49:198:68 | 15535773470978271326 | 15535773470978271326 | +| test.cs:199:5:199:24 | 15587050164583443069 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:5:199:24 | 15587050164583443069 | 15587050164583443069 | +| test.cs:199:27:199:44 | 155978580751494388 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:27:199:44 | 155978580751494388 | 155978580751494388 | +| test.cs:199:47:199:66 | 15695338751700748390 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:47:199:66 | 15695338751700748390 | 15695338751700748390 | +| test.cs:199:69:199:88 | 15997665423159927228 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:199:69:199:88 | 15997665423159927228 | 15997665423159927228 | +| test.cs:200:5:200:24 | 16066522799090129502 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:5:200:24 | 16066522799090129502 | 16066522799090129502 | +| test.cs:200:27:200:46 | 16066651430762394116 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:27:200:46 | 16066651430762394116 | 16066651430762394116 | +| test.cs:200:49:200:68 | 16112751343173365533 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:200:49:200:68 | 16112751343173365533 | 16112751343173365533 | +| test.cs:201:5:201:24 | 16130138450758310172 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:5:201:24 | 16130138450758310172 | 16130138450758310172 | +| test.cs:201:27:201:45 | 1614465773938842903 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:27:201:45 | 1614465773938842903 | 1614465773938842903 | +| test.cs:201:48:201:67 | 16292685861617888592 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:48:201:67 | 16292685861617888592 | 16292685861617888592 | +| test.cs:201:70:201:89 | 16335643316870329598 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:201:70:201:89 | 16335643316870329598 | 16335643316870329598 | +| test.cs:202:5:202:24 | 16423314183614230717 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:5:202:24 | 16423314183614230717 | 16423314183614230717 | +| test.cs:202:27:202:46 | 16570804352575357627 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:27:202:46 | 16570804352575357627 | 16570804352575357627 | +| test.cs:202:49:202:67 | 1682585410644922036 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:49:202:67 | 1682585410644922036 | 1682585410644922036 | +| test.cs:202:70:202:89 | 16858955978146406642 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:202:70:202:89 | 16858955978146406642 | 16858955978146406642 | +| test.cs:203:5:203:24 | 16990567851129491937 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:5:203:24 | 16990567851129491937 | 16990567851129491937 | +| test.cs:203:27:203:46 | 17017923349298346219 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:27:203:46 | 17017923349298346219 | 17017923349298346219 | +| test.cs:203:49:203:68 | 17097380490166623672 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:203:49:203:68 | 17097380490166623672 | 17097380490166623672 | +| test.cs:204:5:204:24 | 17109238199226571972 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:5:204:24 | 17109238199226571972 | 17109238199226571972 | +| test.cs:204:27:204:46 | 17204844226884380288 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:27:204:46 | 17204844226884380288 | 17204844226884380288 | +| test.cs:204:49:204:68 | 17291806236368054941 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:204:49:204:68 | 17291806236368054941 | 17291806236368054941 | +| test.cs:205:5:205:24 | 17351543633914244545 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:5:205:24 | 17351543633914244545 | 17351543633914244545 | +| test.cs:205:27:205:46 | 17439059603042731363 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:27:205:46 | 17439059603042731363 | 17439059603042731363 | +| test.cs:205:49:205:68 | 17574002783607647274 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:205:49:205:68 | 17574002783607647274 | 17574002783607647274 | +| test.cs:206:5:206:24 | 17624147599670377042 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:5:206:24 | 17624147599670377042 | 17624147599670377042 | +| test.cs:206:27:206:46 | 17633734304611248415 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:27:206:46 | 17633734304611248415 | 17633734304611248415 | +| test.cs:206:49:206:68 | 17683972236092287897 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:206:49:206:68 | 17683972236092287897 | 17683972236092287897 | +| test.cs:207:5:207:24 | 17849680105131524334 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:5:207:24 | 17849680105131524334 | 17849680105131524334 | +| test.cs:207:27:207:46 | 17939405613729073960 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:27:207:46 | 17939405613729073960 | 17939405613729073960 | +| test.cs:207:49:207:68 | 17956969551821596225 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:207:49:207:68 | 17956969551821596225 | 17956969551821596225 | +| test.cs:208:5:208:24 | 17978774977754553159 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:5:208:24 | 17978774977754553159 | 17978774977754553159 | +| test.cs:208:27:208:46 | 17984632978012874803 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:27:208:46 | 17984632978012874803 | 17984632978012874803 | +| test.cs:208:49:208:68 | 17997967489723066537 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:208:49:208:68 | 17997967489723066537 | 17997967489723066537 | +| test.cs:209:5:209:24 | 18147627057830191163 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:5:209:24 | 18147627057830191163 | 18147627057830191163 | +| test.cs:209:27:209:46 | 18150909006539876521 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:27:209:46 | 18150909006539876521 | 18150909006539876521 | +| test.cs:209:49:209:68 | 18159703063075866524 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:209:49:209:68 | 18159703063075866524 | 18159703063075866524 | +| test.cs:210:5:210:24 | 18246404330670877335 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:5:210:24 | 18246404330670877335 | 18246404330670877335 | +| test.cs:210:27:210:46 | 18294908219222222902 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:27:210:46 | 18294908219222222902 | 18294908219222222902 | +| test.cs:210:49:210:68 | 18392881921099771407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:210:49:210:68 | 18392881921099771407 | 18392881921099771407 | +| test.cs:211:5:211:24 | 18446744073709551613 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:5:211:24 | 18446744073709551613 | 18446744073709551613 | +| test.cs:211:27:211:44 | 191060519014405309 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:27:211:44 | 191060519014405309 | 191060519014405309 | +| test.cs:211:47:211:65 | 2032008861530788751 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:47:211:65 | 2032008861530788751 | 2032008861530788751 | +| test.cs:211:68:211:86 | 2128122064571842954 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:211:68:211:86 | 2128122064571842954 | 2128122064571842954 | +| test.cs:212:5:212:14 | 2147483647 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:5:212:14 | 2147483647 | 2147483647 | +| test.cs:212:17:212:26 | 2147745794 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:17:212:26 | 2147745794 | 2147745794 | +| test.cs:212:29:212:47 | 2380224015317016190 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:29:212:47 | 2380224015317016190 | 2380224015317016190 | +| test.cs:212:50:212:68 | 2478231962306073784 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:212:50:212:68 | 2478231962306073784 | 2478231962306073784 | +| test.cs:213:5:213:23 | 2532538262737333146 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:5:213:23 | 2532538262737333146 | 2532538262737333146 | +| test.cs:213:26:213:44 | 2589926981877829912 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:26:213:44 | 2589926981877829912 | 2589926981877829912 | +| test.cs:213:47:213:65 | 2597124982561782591 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:47:213:65 | 2597124982561782591 | 2597124982561782591 | +| test.cs:213:68:213:86 | 2600364143812063535 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:213:68:213:86 | 2600364143812063535 | 2600364143812063535 | +| test.cs:214:5:214:23 | 2717025511528702475 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:5:214:23 | 2717025511528702475 | 2717025511528702475 | +| test.cs:214:26:214:44 | 2734787258623754862 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:26:214:44 | 2734787258623754862 | 2734787258623754862 | +| test.cs:214:47:214:63 | 27407921587843457 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:47:214:63 | 27407921587843457 | 27407921587843457 | +| test.cs:214:66:214:84 | 2760663353550280147 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:214:66:214:84 | 2760663353550280147 | 2760663353550280147 | +| test.cs:215:5:215:23 | 2797129108883749491 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:5:215:23 | 2797129108883749491 | 2797129108883749491 | +| test.cs:215:26:215:44 | 2810460305047003196 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:26:215:44 | 2810460305047003196 | 2810460305047003196 | +| test.cs:215:47:215:64 | 292198192373389586 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:47:215:64 | 292198192373389586 | 292198192373389586 | +| test.cs:215:67:215:85 | 2934149816356927366 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:215:67:215:85 | 2934149816356927366 | 2934149816356927366 | +| test.cs:216:5:216:23 | 3045986759481489935 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:5:216:23 | 3045986759481489935 | 3045986759481489935 | +| test.cs:216:26:216:44 | 3178468437029279937 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:26:216:44 | 3178468437029279937 | 3178468437029279937 | +| test.cs:216:47:216:65 | 3200333496547938354 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:47:216:65 | 3200333496547938354 | 3200333496547938354 | +| test.cs:216:68:216:86 | 3320026265773918739 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:216:68:216:86 | 3320026265773918739 | 3320026265773918739 | +| test.cs:217:5:217:23 | 3320767229281015341 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:5:217:23 | 3320767229281015341 | 3320767229281015341 | +| test.cs:217:26:217:44 | 3341747963119755850 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:26:217:44 | 3341747963119755850 | 3341747963119755850 | +| test.cs:217:47:217:65 | 3407972863931386250 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:47:217:65 | 3407972863931386250 | 3407972863931386250 | +| test.cs:217:68:217:86 | 3413052607651207697 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:217:68:217:86 | 3413052607651207697 | 3413052607651207697 | +| test.cs:218:5:218:23 | 3413886037471417852 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:5:218:23 | 3413886037471417852 | 3413886037471417852 | +| test.cs:218:26:218:44 | 3421197789791424393 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:26:218:44 | 3421197789791424393 | 3421197789791424393 | +| test.cs:218:47:218:65 | 3421213182954201407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:47:218:65 | 3421213182954201407 | 3421213182954201407 | +| test.cs:218:68:218:86 | 3425260965299690882 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:218:68:218:86 | 3425260965299690882 | 3425260965299690882 | +| test.cs:219:5:219:23 | 3538022140597504361 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:5:219:23 | 3538022140597504361 | 3538022140597504361 | +| test.cs:219:26:219:44 | 3575761800716667678 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:26:219:44 | 3575761800716667678 | 3575761800716667678 | +| test.cs:219:47:219:65 | 3588624367609827560 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:47:219:65 | 3588624367609827560 | 3588624367609827560 | +| test.cs:219:68:219:86 | 3626142665768487764 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:219:68:219:86 | 3626142665768487764 | 3626142665768487764 | +| test.cs:220:5:220:23 | 3642525650883269872 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:5:220:23 | 3642525650883269872 | 3642525650883269872 | +| test.cs:220:26:220:44 | 3656637464651387014 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:26:220:44 | 3656637464651387014 | 3656637464651387014 | +| test.cs:220:47:220:65 | 3660705254426876796 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:47:220:65 | 3660705254426876796 | 3660705254426876796 | +| test.cs:220:68:220:86 | 3769837838875367802 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:220:68:220:86 | 3769837838875367802 | 3769837838875367802 | +| test.cs:221:5:221:23 | 3778500091710709090 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:5:221:23 | 3778500091710709090 | 3778500091710709090 | +| test.cs:221:26:221:44 | 3796405623695665524 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:26:221:44 | 3796405623695665524 | 3796405623695665524 | +| test.cs:221:47:221:65 | 3869935012404164040 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:47:221:65 | 3869935012404164040 | 3869935012404164040 | +| test.cs:221:68:221:86 | 3890769468012566366 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:221:68:221:86 | 3890769468012566366 | 3890769468012566366 | +| test.cs:222:5:222:23 | 3890794756780010537 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:5:222:23 | 3890794756780010537 | 3890794756780010537 | +| test.cs:222:26:222:43 | 397780960855462669 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:26:222:43 | 397780960855462669 | 397780960855462669 | +| test.cs:222:46:222:64 | 4030236413975199654 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:46:222:64 | 4030236413975199654 | 4030236413975199654 | +| test.cs:222:67:222:85 | 4088976323439621041 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:222:67:222:85 | 4088976323439621041 | 4088976323439621041 | +| test.cs:223:5:223:23 | 4454255944391929578 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:5:223:23 | 4454255944391929578 | 4454255944391929578 | +| test.cs:223:26:223:44 | 4501656691368064027 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:26:223:44 | 4501656691368064027 | 4501656691368064027 | +| test.cs:223:47:223:65 | 4578480846255629462 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:47:223:65 | 4578480846255629462 | 4578480846255629462 | +| test.cs:223:68:223:86 | 4821863173800309721 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:223:68:223:86 | 4821863173800309721 | 4821863173800309721 | +| test.cs:224:5:224:23 | 4931721628717906635 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:5:224:23 | 4931721628717906635 | 4931721628717906635 | +| test.cs:224:26:224:43 | 506634811745884560 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:26:224:43 | 506634811745884560 | 506634811745884560 | +| test.cs:224:46:224:64 | 5132256620104998637 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:46:224:64 | 5132256620104998637 | 5132256620104998637 | +| test.cs:224:67:224:85 | 5183687599225757871 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:224:67:224:85 | 5183687599225757871 | 5183687599225757871 | +| test.cs:225:5:225:22 | 521157249538507889 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:5:225:22 | 521157249538507889 | 521157249538507889 | +| test.cs:225:25:225:43 | 5219431737322569038 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:25:225:43 | 5219431737322569038 | 5219431737322569038 | +| test.cs:225:46:225:63 | 541172992193764396 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:46:225:63 | 541172992193764396 | 541172992193764396 | +| test.cs:225:66:225:84 | 5415426428750045503 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:225:66:225:84 | 5415426428750045503 | 5415426428750045503 | +| test.cs:226:5:226:23 | 5449730069165757263 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:5:226:23 | 5449730069165757263 | 5449730069165757263 | +| test.cs:226:26:226:44 | 5587557070429522647 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:26:226:44 | 5587557070429522647 | 5587557070429522647 | +| test.cs:226:47:226:65 | 5614586596107908838 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:47:226:65 | 5614586596107908838 | 5614586596107908838 | +| test.cs:226:68:226:85 | 576626207276463000 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:226:68:226:85 | 576626207276463000 | 576626207276463000 | +| test.cs:227:5:227:23 | 5942282052525294911 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:5:227:23 | 5942282052525294911 | 5942282052525294911 | +| test.cs:227:26:227:44 | 5945487981219695001 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:26:227:44 | 5945487981219695001 | 5945487981219695001 | +| test.cs:227:47:227:65 | 5984963105389676759 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:47:227:65 | 5984963105389676759 | 5984963105389676759 | +| test.cs:227:68:227:85 | 607197993339007484 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:227:68:227:85 | 607197993339007484 | 607197993339007484 | +| test.cs:228:5:228:23 | 6088115528707848728 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:5:228:23 | 6088115528707848728 | 6088115528707848728 | +| test.cs:228:26:228:44 | 6116246686670134098 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:26:228:44 | 6116246686670134098 | 6116246686670134098 | +| test.cs:228:47:228:65 | 6180361713414290679 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:47:228:65 | 6180361713414290679 | 6180361713414290679 | +| test.cs:228:68:228:86 | 6195833633417633900 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:228:68:228:86 | 6195833633417633900 | 6195833633417633900 | +| test.cs:229:5:229:23 | 6274014997237900919 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:5:229:23 | 6274014997237900919 | 6274014997237900919 | +| test.cs:229:26:229:43 | 640589622539783622 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:26:229:43 | 640589622539783622 | 640589622539783622 | +| test.cs:229:46:229:64 | 6461429591783621719 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:46:229:64 | 6461429591783621719 | 6461429591783621719 | +| test.cs:229:67:229:85 | 6491986958834001955 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:229:67:229:85 | 6491986958834001955 | 6491986958834001955 | +| test.cs:230:5:230:23 | 6508141243778577344 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:5:230:23 | 6508141243778577344 | 6508141243778577344 | +| test.cs:230:26:230:44 | 6605813339339102567 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:26:230:44 | 6605813339339102567 | 6605813339339102567 | +| test.cs:230:47:230:64 | 682250828679635420 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:47:230:64 | 682250828679635420 | 682250828679635420 | +| test.cs:230:67:230:85 | 6827032273910657891 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:230:67:230:85 | 6827032273910657891 | 6827032273910657891 | +| test.cs:231:5:231:23 | 6943102301517884811 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:5:231:23 | 6943102301517884811 | 6943102301517884811 | +| test.cs:231:26:231:43 | 700598796416086955 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:26:231:43 | 700598796416086955 | 700598796416086955 | +| test.cs:231:46:231:64 | 7080175711202577138 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:46:231:64 | 7080175711202577138 | 7080175711202577138 | +| test.cs:231:67:231:85 | 7175363135479931834 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:231:67:231:85 | 7175363135479931834 | 7175363135479931834 | +| test.cs:232:5:232:23 | 7315838824213522000 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:5:232:23 | 7315838824213522000 | 7315838824213522000 | +| test.cs:232:26:232:44 | 7412338704062093516 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:26:232:44 | 7412338704062093516 | 7412338704062093516 | +| test.cs:232:47:232:65 | 7516148236133302073 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:47:232:65 | 7516148236133302073 | 7516148236133302073 | +| test.cs:232:68:232:86 | 7574774749059321801 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:232:68:232:86 | 7574774749059321801 | 7574774749059321801 | +| test.cs:233:5:233:23 | 7701683279824397773 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:5:233:23 | 7701683279824397773 | 7701683279824397773 | +| test.cs:233:26:233:44 | 7775177810774851294 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:26:233:44 | 7775177810774851294 | 7775177810774851294 | +| test.cs:233:47:233:65 | 7810436520414958497 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:47:233:65 | 7810436520414958497 | 7810436520414958497 | +| test.cs:233:68:233:86 | 7878537243757499832 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:233:68:233:86 | 7878537243757499832 | 7878537243757499832 | +| test.cs:234:5:234:21 | 79089792725215063 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:5:234:21 | 79089792725215063 | 79089792725215063 | +| test.cs:234:24:234:42 | 7982848972385914508 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:24:234:42 | 7982848972385914508 | 7982848972385914508 | +| test.cs:234:45:234:63 | 8052533790968282297 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:45:234:63 | 8052533790968282297 | 8052533790968282297 | +| test.cs:234:66:234:84 | 8129411991672431889 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:234:66:234:84 | 8129411991672431889 | 8129411991672431889 | +| test.cs:235:5:235:23 | 8146185202538899243 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:5:235:23 | 8146185202538899243 | 8146185202538899243 | +| test.cs:235:26:235:43 | 835151375515278827 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:26:235:43 | 835151375515278827 | 835151375515278827 | +| test.cs:235:46:235:64 | 8381292265993977266 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:46:235:64 | 8381292265993977266 | 8381292265993977266 | +| test.cs:235:67:235:85 | 8408095252303317471 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:235:67:235:85 | 8408095252303317471 | 8408095252303317471 | +| test.cs:236:5:236:23 | 8473756179280619170 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:5:236:23 | 8473756179280619170 | 8473756179280619170 | +| test.cs:236:26:236:44 | 8478833628889826985 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:26:236:44 | 8478833628889826985 | 8478833628889826985 | +| test.cs:236:47:236:65 | 8612208440357175863 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:47:236:65 | 8612208440357175863 | 8612208440357175863 | +| test.cs:236:68:236:86 | 8697424601205169055 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:236:68:236:86 | 8697424601205169055 | 8697424601205169055 | +| test.cs:237:5:237:23 | 8698326794961817906 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:5:237:23 | 8698326794961817906 | 8698326794961817906 | +| test.cs:237:26:237:44 | 8709004393777297355 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:26:237:44 | 8709004393777297355 | 8709004393777297355 | +| test.cs:237:47:237:65 | 8727477769544302060 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:47:237:65 | 8727477769544302060 | 8727477769544302060 | +| test.cs:237:68:237:86 | 8760312338504300643 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:237:68:237:86 | 8760312338504300643 | 8760312338504300643 | +| test.cs:238:5:238:23 | 8799118153397725683 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:5:238:23 | 8799118153397725683 | 8799118153397725683 | +| test.cs:238:26:238:44 | 8873858923435176895 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:26:238:44 | 8873858923435176895 | 8873858923435176895 | +| test.cs:238:47:238:65 | 8994091295115840290 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:47:238:65 | 8994091295115840290 | 8994091295115840290 | +| test.cs:238:68:238:86 | 9007106680104765185 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:238:68:238:86 | 9007106680104765185 | 9007106680104765185 | +| test.cs:239:5:239:23 | 9061219083560670602 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:5:239:23 | 9061219083560670602 | 9061219083560670602 | +| test.cs:239:26:239:44 | 9149947745824492274 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:26:239:44 | 9149947745824492274 | 9149947745824492274 | +| test.cs:239:47:239:64 | 917638920165491138 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:47:239:64 | 917638920165491138 | 917638920165491138 | +| test.cs:239:67:239:85 | 9234894663364701749 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:239:67:239:85 | 9234894663364701749 | 9234894663364701749 | +| test.cs:240:5:240:23 | 9333057603143916814 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:5:240:23 | 9333057603143916814 | 9333057603143916814 | +| test.cs:240:26:240:44 | 9384605490088500348 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:26:240:44 | 9384605490088500348 | 9384605490088500348 | +| test.cs:240:47:240:65 | 9531326785919727076 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:47:240:65 | 9531326785919727076 | 9531326785919727076 | +| test.cs:240:68:240:86 | 9555688264681862794 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:240:68:240:86 | 9555688264681862794 | 9555688264681862794 | +| test.cs:241:5:241:23 | 9559632696372799208 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:241:5:241:23 | 9559632696372799208 | 9559632696372799208 | +| test.cs:241:26:241:44 | 9903758755917170407 | The Hash literal $@ may be related to the Solorigate campaign. Total count = 243 is above the threshold 5. | test.cs:241:26:241:44 | 9903758755917170407 | 9903758755917170407 | diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qlref b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qlref new file mode 100644 index 00000000000..0b468dcce55 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qlref @@ -0,0 +1 @@ +experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected new file mode 100644 index 00000000000..043068419d7 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.expected @@ -0,0 +1,140 @@ +| test.cs:247:4:247:35 | "(?i)([^a-z]\|^)(test)([^a-z]\|$)" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:4:247:35 | "(?i)([^a-z]\|^)(test)([^a-z]\|$)" | (?i)([^a-z]\|^)(test)([^a-z]\|$) | +| test.cs:247:38:247:55 | "(?i)(solarwinds)" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:38:247:55 | "(?i)(solarwinds)" | (?i)(solarwinds) | +| test.cs:247:58:247:96 | "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:247:58:247:96 | "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n" | [{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n | +| test.cs:248:4:248:18 | "[{0,5}] {1}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:4:248:18 | "[{0,5}] {1}\n" | [{0,5}] {1}\n | +| test.cs:248:21:248:37 | "[E] {0} {1} {2}" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:248:21:248:37 | "[E] {0} {1} {2}" | [E] {0} {1} {2} | +| test.cs:249:4:249:62 | "\\"\\{[0-9a-f-]{36}\\}\\"\|\\"[0-9a-f]{32}\\"\|\\"[0-9a-f]{16}\\"" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:4:249:62 | "\\"\\{[0-9a-f-]{36}\\}\\"\|\\"[0-9a-f]{32}\\"\|\\"[0-9a-f]{16}\\"" | "\\{[0-9a-f-]{36}\\}"\|"[0-9a-f]{32}"\|"[0-9a-f]{16}" | +| test.cs:249:65:249:79 | ".CortexPlugin" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:65:249:79 | ".CortexPlugin" | .CortexPlugin | +| test.cs:249:82:249:89 | ".Orion" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:249:82:249:89 | ".Orion" | .Orion | +| test.cs:250:4:250:36 | "\\"EventName\\":\\"EventManager\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:250:4:250:36 | "\\"EventName\\":\\"EventManager\\"," | "EventName":"EventManager", | +| test.cs:250:39:250:64 | "\\"EventType\\":\\"Orion\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:250:39:250:64 | "\\"EventType\\":\\"Orion\\"," | "EventType":"Orion", | +| test.cs:251:4:251:56 | "\\OrionImprovement\\SolarWinds.OrionImprovement.exe" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:251:4:251:56 | "\\OrionImprovement\\SolarWinds.OrionImprovement.exe" | \\OrionImprovement\\SolarWinds.OrionImprovement.exe | +| test.cs:252:4:252:44 | "0123456789abcdefghijklmnopqrstuvwxyz-_." | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:4:252:44 | "0123456789abcdefghijklmnopqrstuvwxyz-_." | 0123456789abcdefghijklmnopqrstuvwxyz-_. | +| test.cs:252:47:252:70 | "\\"sessionId\\":\\"{0}\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:47:252:70 | "\\"sessionId\\":\\"{0}\\"," | "sessionId":"{0}", | +| test.cs:252:73:252:85 | "\\"steps\\":[" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:252:73:252:85 | "\\"steps\\":[" | "steps":[ | +| test.cs:253:4:253:24 | "\\"Succeeded\\":true," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:4:253:24 | "\\"Succeeded\\":true," | "Succeeded":true, | +| test.cs:253:27:253:62 | "\\"Timestamp\\":\\"\\/Date({0})\\/\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:27:253:62 | "\\"Timestamp\\":\\"\\/Date({0})\\/\\"," | "Timestamp":"\\/Date({0})\\/", | +| test.cs:253:65:253:85 | "\\"userId\\":\\"{0}\\"," | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:253:65:253:85 | "\\"userId\\":\\"{0}\\"," | "userId":"{0}", | +| test.cs:254:4:254:23 | "{0} {1} HTTP/{2}\n" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:4:254:23 | "{0} {1} HTTP/{2}\n" | {0} {1} HTTP/{2}\n | +| test.cs:254:26:254:32 | "10140" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:26:254:32 | "10140" | 10140 | +| test.cs:254:35:254:48 | "144.86.226.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:35:254:48 | "144.86.226.0" | 144.86.226.0 | +| test.cs:254:51:254:65 | "154.118.140.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:51:254:65 | "154.118.140.0" | 154.118.140.0 | +| test.cs:254:68:254:79 | "172.16.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:68:254:79 | "172.16.0.0" | 172.16.0.0 | +| test.cs:254:82:254:93 | "18.130.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:254:82:254:93 | "18.130.0.0" | 18.130.0.0 | +| test.cs:255:4:255:15 | "184.72.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:4:255:15 | "184.72.0.0" | 184.72.0.0 | +| test.cs:255:18:255:30 | "192.168.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:18:255:30 | "192.168.0.0" | 192.168.0.0 | +| test.cs:255:33:255:47 | "199.201.117.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:33:255:47 | "199.201.117.0" | 199.201.117.0 | +| test.cs:255:50:255:61 | "20.140.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:50:255:61 | "20.140.0.0" | 20.140.0.0 | +| test.cs:255:64:255:70 | "20100" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:64:255:70 | "20100" | 20100 | +| test.cs:255:73:255:79 | "20220" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:73:255:79 | "20220" | 20220 | +| test.cs:255:82:255:94 | "217.163.7.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:255:82:255:94 | "217.163.7.0" | 217.163.7.0 | +| test.cs:256:4:256:14 | "224.0.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:4:256:14 | "224.0.0.0" | 224.0.0.0 | +| test.cs:256:17:256:27 | "240.0.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:17:256:27 | "240.0.0.0" | 240.0.0.0 | +| test.cs:256:30:256:42 | "255.240.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:30:256:42 | "255.240.0.0" | 255.240.0.0 | +| test.cs:256:45:256:57 | "255.254.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:45:256:57 | "255.254.0.0" | 255.254.0.0 | +| test.cs:256:60:256:74 | "255.255.248.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:60:256:74 | "255.255.248.0" | 255.255.248.0 | +| test.cs:256:77:256:87 | "3.0.0.382" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:256:77:256:87 | "3.0.0.382" | 3.0.0.382 | +| test.cs:257:4:257:16 | "41.84.159.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:4:257:16 | "41.84.159.0" | 41.84.159.0 | +| test.cs:257:19:257:25 | "43140" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:19:257:25 | "43140" | 43140 | +| test.cs:257:28:257:33 | "4320" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:28:257:33 | "4320" | 4320 | +| test.cs:257:36:257:42 | "43260" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:36:257:42 | "43260" | 43260 | +| test.cs:257:45:257:52 | "524287" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:45:257:52 | "524287" | 524287 | +| test.cs:257:55:257:92 | "583da945-62af-10e8-4902-a8f205c72b2e" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:257:55:257:92 | "583da945-62af-10e8-4902-a8f205c72b2e" | 583da945-62af-10e8-4902-a8f205c72b2e | +| test.cs:258:4:258:10 | "65280" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:4:258:10 | "65280" | 65280 | +| test.cs:258:13:258:25 | "71.152.53.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:13:258:25 | "71.152.53.0" | 71.152.53.0 | +| test.cs:258:28:258:40 | "74.114.24.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:28:258:40 | "74.114.24.0" | 74.114.24.0 | +| test.cs:258:43:258:54 | "8.18.144.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:43:258:54 | "8.18.144.0" | 8.18.144.0 | +| test.cs:258:57:258:69 | "87.238.80.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:57:258:69 | "87.238.80.0" | 87.238.80.0 | +| test.cs:258:72:258:84 | "96.31.172.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:72:258:84 | "96.31.172.0" | 96.31.172.0 | +| test.cs:258:87:258:94 | "983040" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:258:87:258:94 | "983040" | 983040 | +| test.cs:259:4:259:14 | "99.79.0.0" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:4:259:14 | "99.79.0.0" | 99.79.0.0 | +| test.cs:259:17:259:31 | "Administrator" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:17:259:31 | "Administrator" | Administrator | +| test.cs:259:34:259:47 | "advapi32.dll" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:34:259:47 | "advapi32.dll" | advapi32.dll | +| test.cs:259:50:259:57 | "Apollo" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:50:259:57 | "Apollo" | Apollo | +| test.cs:259:60:259:72 | "appsync-api" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:60:259:72 | "appsync-api" | appsync-api | +| test.cs:259:75:259:90 | "avsvmcloud.com" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:259:75:259:90 | "avsvmcloud.com" | avsvmcloud.com | +| test.cs:260:4:260:23 | "api.solarwinds.com" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:4:260:23 | "api.solarwinds.com" | api.solarwinds.com | +| test.cs:260:26:260:32 | "-root" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:26:260:32 | "-root" | -root | +| test.cs:260:35:260:41 | "-cert" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:35:260:41 | "-cert" | -cert | +| test.cs:260:44:260:58 | "-universal_ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:44:260:58 | "-universal_ca" | -universal_ca | +| test.cs:260:61:260:65 | "-ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:61:260:65 | "-ca" | -ca | +| test.cs:260:68:260:80 | "-primary_ca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:68:260:80 | "-primary_ca" | -primary_ca | +| test.cs:260:83:260:94 | "-timestamp" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:260:83:260:94 | "-timestamp" | -timestamp | +| test.cs:261:4:261:12 | "-global" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:4:261:12 | "-global" | -global | +| test.cs:261:15:261:25 | "-secureca" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:15:261:25 | "-secureca" | -secureca | +| test.cs:261:28:261:44 | "CloudMonitoring" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:28:261:44 | "CloudMonitoring" | CloudMonitoring | +| test.cs:261:47:261:58 | "MACAddress" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:47:261:58 | "MACAddress" | MACAddress | +| test.cs:261:61:261:73 | "DHCPEnabled" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:61:261:73 | "DHCPEnabled" | DHCPEnabled | +| test.cs:261:76:261:87 | "DHCPServer" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:261:76:261:87 | "DHCPServer" | DHCPServer | +| test.cs:262:4:262:16 | "DNSHostName" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:4:262:16 | "DNSHostName" | DNSHostName | +| test.cs:262:19:262:46 | "DNSDomainSuffixSearchOrder" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:19:262:46 | "DNSDomainSuffixSearchOrder" | DNSDomainSuffixSearchOrder | +| test.cs:262:49:262:70 | "DNSServerSearchOrder" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:49:262:70 | "DNSServerSearchOrder" | DNSServerSearchOrder | +| test.cs:262:73:262:83 | "IPAddress" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:73:262:83 | "IPAddress" | IPAddress | +| test.cs:262:86:262:95 | "IPSubnet" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:262:86:262:95 | "IPSubnet" | IPSubnet | +| test.cs:263:4:263:21 | "DefaultIPGateway" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:4:263:21 | "DefaultIPGateway" | DefaultIPGateway | +| test.cs:263:24:263:39 | "OSArchitecture" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:24:263:39 | "OSArchitecture" | OSArchitecture | +| test.cs:263:42:263:54 | "InstallDate" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:42:263:54 | "InstallDate" | InstallDate | +| test.cs:263:57:263:70 | "Organization" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:57:263:70 | "Organization" | Organization | +| test.cs:263:73:263:88 | "RegisteredUser" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:263:73:263:88 | "RegisteredUser" | RegisteredUser | +| test.cs:264:4:264:11 | "fc00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:4:264:11 | "fc00::" | fc00:: | +| test.cs:264:14:264:21 | "fe00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:14:264:21 | "fe00::" | fe00:: | +| test.cs:264:24:264:31 | "fec0::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:24:264:31 | "fec0::" | fec0:: | +| test.cs:264:34:264:41 | "ffc0::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:34:264:41 | "ffc0::" | ffc0:: | +| test.cs:264:44:264:51 | "ff00::" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:44:264:51 | "ff00::" | ff00:: | +| test.cs:264:54:264:59 | "HKCC" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:54:264:59 | "HKCC" | HKCC | +| test.cs:264:62:264:67 | "HKCR" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:62:264:67 | "HKCR" | HKCR | +| test.cs:264:70:264:75 | "HKCU" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:70:264:75 | "HKCU" | HKCU | +| test.cs:264:78:264:83 | "HKDD" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:264:78:264:83 | "HKDD" | HKDD | +| test.cs:265:4:265:22 | "HKEY_CLASSES_ROOT" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:4:265:22 | "HKEY_CLASSES_ROOT" | HKEY_CLASSES_ROOT | +| test.cs:265:25:265:45 | "HKEY_CURRENT_CONFIG" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:25:265:45 | "HKEY_CURRENT_CONFIG" | HKEY_CURRENT_CONFIG | +| test.cs:265:48:265:66 | "HKEY_CURRENT_USER" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:48:265:66 | "HKEY_CURRENT_USER" | HKEY_CURRENT_USER | +| test.cs:265:69:265:83 | "HKEY_DYN_DATA" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:265:69:265:83 | "HKEY_DYN_DATA" | HKEY_DYN_DATA | +| test.cs:266:4:266:23 | "HKEY_LOCAL_MACHINE" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:4:266:23 | "HKEY_LOCAL_MACHINE" | HKEY_LOCAL_MACHINE | +| test.cs:266:26:266:80 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:266:26:266:80 | "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" | HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography | +| test.cs:267:4:267:25 | "HKEY_PERFOMANCE_DATA" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:4:267:25 | "HKEY_PERFOMANCE_DATA" | HKEY_PERFOMANCE_DATA | +| test.cs:267:28:267:39 | "HKEY_USERS" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:28:267:39 | "HKEY_USERS" | HKEY_USERS | +| test.cs:267:42:267:47 | "HKLM" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:42:267:47 | "HKLM" | HKLM | +| test.cs:267:50:267:55 | "HKPD" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:50:267:55 | "HKPD" | HKPD | +| test.cs:267:58:267:62 | "HKU" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:58:267:62 | "HKU" | HKU | +| test.cs:267:65:267:79 | "If-None-Match" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:267:65:267:79 | "If-None-Match" | If-None-Match | +| test.cs:268:4:268:25 | "Microsoft-CryptoAPI/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:4:268:25 | "Microsoft-CryptoAPI/" | Microsoft-CryptoAPI/ | +| test.cs:268:28:268:34 | "Nodes" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:28:268:34 | "Nodes" | Nodes | +| test.cs:268:37:268:45 | "Volumes" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:37:268:45 | "Volumes" | Volumes | +| test.cs:268:48:268:59 | "Interfaces" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:48:268:59 | "Interfaces" | Interfaces | +| test.cs:268:62:268:73 | "Components" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:62:268:73 | "Components" | Components | +| test.cs:268:76:268:85 | "opensans" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:268:76:268:85 | "opensans" | opensans | +| test.cs:269:4:269:17 | "Organization" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:4:269:17 | "Organization" | Organization | +| test.cs:269:20:269:35 | "OSArchitecture" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:20:269:35 | "OSArchitecture" | OSArchitecture | +| test.cs:269:38:269:54 | "ParentProcessID" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:38:269:54 | "ParentProcessID" | ParentProcessID | +| test.cs:269:57:269:66 | "PathName" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:57:269:66 | "PathName" | PathName | +| test.cs:269:69:269:91 | "ReportWatcherPostpone" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:269:69:269:91 | "ReportWatcherPostpone" | ReportWatcherPostpone | +| test.cs:270:4:270:23 | "ReportWatcherRetry" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:4:270:23 | "ReportWatcherRetry" | ReportWatcherRetry | +| test.cs:270:26:270:33 | "S-1-5-" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:26:270:33 | "S-1-5-" | S-1-5- | +| test.cs:270:36:270:55 | "SeRestorePrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:36:270:55 | "SeRestorePrivilege" | SeRestorePrivilege | +| test.cs:270:58:270:78 | "SeShutdownPrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:270:58:270:78 | "SeShutdownPrivilege" | SeShutdownPrivilege | +| test.cs:271:4:271:29 | "SeTakeOwnershipPrivilege" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:4:271:29 | "SeTakeOwnershipPrivilege" | SeTakeOwnershipPrivilege | +| test.cs:271:32:271:43 | "SolarWinds" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:32:271:43 | "SolarWinds" | SolarWinds | +| test.cs:271:46:271:80 | "SolarWindsOrionImprovementClient/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:271:46:271:80 | "SolarWindsOrionImprovementClient/" | SolarWindsOrionImprovementClient/ | +| test.cs:272:4:272:18 | "SourceCodePro" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:4:272:18 | "SourceCodePro" | SourceCodePro | +| test.cs:272:21:272:35 | "SourceHanSans" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:21:272:35 | "SourceHanSans" | SourceHanSans | +| test.cs:272:38:272:53 | "SourceHanSerif" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:38:272:53 | "SourceHanSerif" | SourceHanSerif | +| test.cs:272:56:272:71 | "SourceSerifPro" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:56:272:71 | "SourceSerifPro" | SourceSerifPro | +| test.cs:272:74:272:80 | "Start" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:74:272:80 | "Start" | Start | +| test.cs:272:83:272:95 | "swip/Events" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:272:83:272:95 | "swip/Events" | swip/Events | +| test.cs:273:4:273:14 | "swip/upd/" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:4:273:14 | "swip/upd/" | swip/upd/ | +| test.cs:273:17:273:34 | "swip/Upload.ashx" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:17:273:34 | "swip/Upload.ashx" | swip/Upload.ashx | +| test.cs:273:37:273:44 | "SYSTEM" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:37:273:44 | "SYSTEM" | SYSTEM | +| test.cs:273:47:273:83 | "SYSTEM\\CurrentControlSet\\services" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:47:273:83 | "SYSTEM\\CurrentControlSet\\services" | SYSTEM\\CurrentControlSet\\services | +| test.cs:273:86:273:96 | "us-east-1" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:273:86:273:96 | "us-east-1" | us-east-1 | +| test.cs:274:4:274:14 | "us-east-2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:4:274:14 | "us-east-2" | us-east-2 | +| test.cs:274:17:274:27 | "us-west-2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:17:274:27 | "us-west-2" | us-west-2 | +| test.cs:274:30:274:62 | "fonts/woff/{0}-{1}-{2}{3}.woff2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:274:30:274:62 | "fonts/woff/{0}-{1}-{2}{3}.woff2" | fonts/woff/{0}-{1}-{2}{3}.woff2 | +| test.cs:275:4:275:44 | "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:275:4:275:44 | "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2" | fonts/woff/{0}-{1}-{2}-webfont{3}.woff2 | +| test.cs:275:47:275:80 | "ph2eifo3n5utg1j8d94qrvbmk0sal76c" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:275:47:275:80 | "ph2eifo3n5utg1j8d94qrvbmk0sal76c" | ph2eifo3n5utg1j8d94qrvbmk0sal76c | +| test.cs:276:4:276:26 | "pki/crl/{0}{1}{2}.crl" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:276:4:276:26 | "pki/crl/{0}{1}{2}.crl" | pki/crl/{0}{1}{2}.crl | +| test.cs:276:29:276:65 | "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:276:29:276:65 | "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj" | rq3gsalt6u1iyfzop572d49bnx8cvmkewhj | +| test.cs:277:4:277:73 | "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:277:4:277:73 | "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true" | Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true | +| test.cs:278:4:278:40 | "Select * From Win32_OperatingSystem" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:278:4:278:40 | "Select * From Win32_OperatingSystem" | Select * From Win32_OperatingSystem | +| test.cs:278:43:278:71 | "Select * From Win32_Process" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:278:43:278:71 | "Select * From Win32_Process" | Select * From Win32_Process | +| test.cs:279:4:279:37 | "Select * From Win32_SystemDriver" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:279:4:279:37 | "Select * From Win32_SystemDriver" | Select * From Win32_SystemDriver | +| test.cs:279:40:279:72 | "Select * From Win32_UserAccount" | The literal $@ may be related to the Solorigate campaign. Total count = 138 is above the threshold 30. | test.cs:279:40:279:72 | "Select * From Win32_UserAccount" | Select * From Win32_UserAccount | diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qlref b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qlref new file mode 100644 index 00000000000..e3c8a3b7f87 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qlref @@ -0,0 +1 @@ +experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected new file mode 100644 index 00000000000..625fe686581 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.expected @@ -0,0 +1,104 @@ +| test.cs:66:7:66:11 | Abort | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:66:7:66:11 | Abort | Abort | +| test.cs:67:7:67:28 | AddFileExecutionEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:67:7:67:28 | AddFileExecutionEngine | AddFileExecutionEngine | +| test.cs:68:7:68:32 | AddRegistryExecutionEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:68:7:68:32 | AddRegistryExecutionEngine | AddRegistryExecutionEngine | +| test.cs:69:7:69:27 | AdjustTokenPrivileges | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:69:7:69:27 | AdjustTokenPrivileges | AdjustTokenPrivileges | +| test.cs:70:7:70:18 | Base64Decode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:70:7:70:18 | Base64Decode | Base64Decode | +| test.cs:71:7:71:18 | Base64Encode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:71:7:71:18 | Base64Encode | Base64Encode | +| test.cs:72:7:72:26 | ByteArrayToHexString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:72:7:72:26 | ByteArrayToHexString | ByteArrayToHexString | +| test.cs:73:7:73:27 | CheckServerConnection | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:73:7:73:27 | CheckServerConnection | CheckServerConnection | +| test.cs:74:7:74:11 | Close | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:74:7:74:11 | Close | Close | +| test.cs:75:7:75:17 | CloseHandle | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:75:7:75:17 | CloseHandle | CloseHandle | +| test.cs:76:7:76:30 | CollectSystemDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:76:7:76:30 | CollectSystemDescription | CollectSystemDescription | +| test.cs:77:7:77:14 | Compress | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:77:7:77:14 | Compress | Compress | +| test.cs:78:7:78:24 | CreateSecureString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:78:7:78:24 | CreateSecureString | CreateSecureString | +| test.cs:79:7:79:18 | CreateString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:79:7:79:18 | CreateString | CreateString | +| test.cs:80:7:80:25 | CreateUploadRequest | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:80:7:80:25 | CreateUploadRequest | CreateUploadRequest | +| test.cs:81:7:81:29 | CreateUploadRequestImpl | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:81:7:81:29 | CreateUploadRequestImpl | CreateUploadRequestImpl | +| test.cs:82:7:82:16 | Decompress | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:82:7:82:16 | Decompress | Decompress | +| test.cs:83:7:83:18 | DecryptShort | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:83:7:83:18 | DecryptShort | DecryptShort | +| test.cs:84:7:84:13 | Deflate | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:84:7:84:13 | Deflate | Deflate | +| test.cs:85:7:85:14 | DelayMin | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:85:7:85:14 | DelayMin | DelayMin | +| test.cs:86:7:86:13 | DelayMs | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:86:7:86:13 | DelayMs | DelayMs | +| test.cs:87:7:87:16 | DeleteFile | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:87:7:87:16 | DeleteFile | DeleteFile | +| test.cs:88:7:88:25 | DeleteRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:88:7:88:25 | DeleteRegistryValue | DeleteRegistryValue | +| test.cs:89:7:89:17 | DeleteValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:89:7:89:17 | DeleteValue | DeleteValue | +| test.cs:90:7:90:19 | ExecuteEngine | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:90:7:90:19 | ExecuteEngine | ExecuteEngine | +| test.cs:91:7:91:16 | FileExists | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:91:7:91:16 | FileExists | FileExists | +| test.cs:92:7:92:18 | GetAddresses | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:92:7:92:18 | GetAddresses | GetAddresses | +| test.cs:93:7:93:22 | GetAddressFamily | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:93:7:93:22 | GetAddressFamily | GetAddressFamily | +| test.cs:94:7:94:22 | GetArgumentIndex | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:94:7:94:22 | GetArgumentIndex | GetArgumentIndex | +| test.cs:95:7:95:16 | GetBaseUri | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:95:7:95:16 | GetBaseUri | GetBaseUri | +| test.cs:96:7:96:20 | GetBaseUriImpl | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:96:7:96:20 | GetBaseUriImpl | GetBaseUriImpl | +| test.cs:97:7:97:14 | GetCache | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:97:7:97:14 | GetCache | GetCache | +| test.cs:98:7:98:23 | GetCurrentProcess | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:98:7:98:23 | GetCurrentProcess | GetCurrentProcess | +| test.cs:99:7:99:22 | GetCurrentString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:99:7:99:22 | GetCurrentString | GetCurrentString | +| test.cs:100:7:100:22 | GetDescriptionId | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:100:7:100:22 | GetDescriptionId | GetDescriptionId | +| test.cs:101:7:101:17 | GetFileHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:101:7:101:17 | GetFileHash | GetFileHash | +| test.cs:102:7:102:26 | GetFileSystemEntries | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:102:7:102:26 | GetFileSystemEntries | GetFileSystemEntries | +| test.cs:103:7:103:13 | GetHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:103:7:103:13 | GetHash | GetHash | +| test.cs:104:7:104:13 | GetHive | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:104:7:104:13 | GetHive | GetHive | +| test.cs:105:7:105:17 | GetIntArray | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:105:7:105:17 | GetIntArray | GetIntArray | +| test.cs:106:7:106:20 | GetIPHostEntry | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:106:7:106:20 | GetIPHostEntry | GetIPHostEntry | +| test.cs:107:7:107:33 | GetManagementObjectProperty | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:107:7:107:33 | GetManagementObjectProperty | GetManagementObjectProperty | +| test.cs:108:7:108:36 | GetNetworkAdapterConfiguration | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:108:7:108:36 | GetNetworkAdapterConfiguration | GetNetworkAdapterConfiguration | +| test.cs:109:7:109:21 | GetNewOwnerName | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:109:7:109:21 | GetNewOwnerName | GetNewOwnerName | +| test.cs:110:7:110:19 | GetNextString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:110:7:110:19 | GetNextString | GetNextString | +| test.cs:111:7:111:21 | GetNextStringEx | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:111:7:111:21 | GetNextStringEx | GetNextStringEx | +| test.cs:112:7:112:23 | GetOrCreateUserID | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:112:7:112:23 | GetOrCreateUserID | GetOrCreateUserID | +| test.cs:113:7:113:35 | GetOrionImprovementCustomerId | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:113:7:113:35 | GetOrionImprovementCustomerId | GetOrionImprovementCustomerId | +| test.cs:114:7:114:18 | GetOSVersion | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:114:7:114:18 | GetOSVersion | GetOSVersion | +| test.cs:115:7:115:23 | GetPreviousString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:115:7:115:23 | GetPreviousString | GetPreviousString | +| test.cs:116:7:116:29 | GetProcessByDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:116:7:116:29 | GetProcessByDescription | GetProcessByDescription | +| test.cs:117:7:117:36 | GetRegistrySubKeyAndValueNames | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:117:7:117:36 | GetRegistrySubKeyAndValueNames | GetRegistrySubKeyAndValueNames | +| test.cs:118:7:118:15 | GetStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:118:7:118:15 | GetStatus | GetStatus | +| test.cs:119:7:119:19 | GetStringHash | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:119:7:119:19 | GetStringHash | GetStringHash | +| test.cs:120:7:120:28 | GetSubKeyAndValueNames | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:120:7:120:28 | GetSubKeyAndValueNames | GetSubKeyAndValueNames | +| test.cs:121:7:121:18 | GetUserAgent | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:121:7:121:18 | GetUserAgent | GetUserAgent | +| test.cs:122:7:122:14 | GetValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:122:7:122:14 | GetValue | GetValue | +| test.cs:123:7:123:17 | GetWebProxy | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:123:7:123:17 | GetWebProxy | GetWebProxy | +| test.cs:124:7:124:26 | HexStringToByteArray | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:124:7:124:26 | HexStringToByteArray | HexStringToByteArray | +| test.cs:125:7:125:13 | Inflate | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:125:7:125:13 | Inflate | Inflate | +| test.cs:126:7:126:16 | Initialize | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:126:7:126:16 | Initialize | Initialize | +| test.cs:127:7:127:31 | InitiateSystemShutdownExW | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:127:7:127:31 | InitiateSystemShutdownExW | InitiateSystemShutdownExW | +| test.cs:128:7:128:25 | IsNullOrInvalidName | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:128:7:128:25 | IsNullOrInvalidName | IsNullOrInvalidName | +| test.cs:129:7:129:20 | IsSynchronized | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:129:7:129:20 | IsSynchronized | IsSynchronized | +| test.cs:130:7:130:14 | KillTask | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:130:7:130:14 | KillTask | KillTask | +| test.cs:131:7:131:27 | LookupPrivilegeValueW | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:131:7:131:27 | LookupPrivilegeValueW | LookupPrivilegeValueW | +| test.cs:132:7:132:22 | OpenProcessToken | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:132:7:132:22 | OpenProcessToken | OpenProcessToken | +| test.cs:133:7:133:26 | ParseServiceResponse | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:133:7:133:26 | ParseServiceResponse | ParseServiceResponse | +| test.cs:134:7:134:11 | Quote | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:134:7:134:11 | Quote | Quote | +| test.cs:135:7:135:16 | ReadConfig | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:135:7:135:16 | ReadConfig | ReadConfig | +| test.cs:136:7:136:20 | ReadDeviceInfo | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:136:7:136:20 | ReadDeviceInfo | ReadDeviceInfo | +| test.cs:137:7:137:23 | ReadRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:137:7:137:23 | ReadRegistryValue | ReadRegistryValue | +| test.cs:138:7:138:22 | ReadReportStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:138:7:138:22 | ReadReportStatus | ReadReportStatus | +| test.cs:139:7:139:23 | ReadServiceStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:139:7:139:23 | ReadServiceStatus | ReadServiceStatus | +| test.cs:140:7:140:20 | RebootComputer | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:140:7:140:20 | RebootComputer | RebootComputer | +| test.cs:141:7:141:13 | RunTask | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:141:7:141:13 | RunTask | RunTask | +| test.cs:142:7:142:22 | SearchAssemblies | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:142:7:142:22 | SearchAssemblies | SearchAssemblies | +| test.cs:143:7:143:26 | SearchConfigurations | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:143:7:143:26 | SearchConfigurations | SearchConfigurations | +| test.cs:144:7:144:20 | SearchServices | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:144:7:144:20 | SearchServices | SearchServices | +| test.cs:145:7:145:22 | SetAutomaticMode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:145:7:145:22 | SetAutomaticMode | SetAutomaticMode | +| test.cs:146:7:146:17 | SetKeyOwner | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:146:7:146:17 | SetKeyOwner | SetKeyOwner | +| test.cs:147:7:147:31 | SetKeyOwnerWithPrivileges | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:147:7:147:31 | SetKeyOwnerWithPrivileges | SetKeyOwnerWithPrivileges | +| test.cs:148:7:148:23 | SetKeyPermissions | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:148:7:148:23 | SetKeyPermissions | SetKeyPermissions | +| test.cs:149:7:149:19 | SetManualMode | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:149:7:149:19 | SetManualMode | SetManualMode | +| test.cs:150:7:150:25 | SetProcessPrivilege | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:150:7:150:25 | SetProcessPrivilege | SetProcessPrivilege | +| test.cs:151:7:151:22 | SetRegistryValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:151:7:151:22 | SetRegistryValue | SetRegistryValue | +| test.cs:152:7:152:13 | SetTime | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:152:7:152:13 | SetTime | SetTime | +| test.cs:153:7:153:14 | SetValue | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:153:7:153:14 | SetValue | SetValue | +| test.cs:154:7:154:17 | SplitString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:154:7:154:17 | SplitString | SplitString | +| test.cs:155:7:155:14 | ToString | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:155:7:155:14 | ToString | ToString | +| test.cs:156:7:156:16 | TrackEvent | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:156:7:156:16 | TrackEvent | TrackEvent | +| test.cs:157:7:157:20 | TrackProcesses | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:157:7:157:20 | TrackProcesses | TrackProcesses | +| test.cs:158:7:158:13 | Unquote | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:158:7:158:13 | Unquote | Unquote | +| test.cs:159:7:159:11 | Unzip | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:159:7:159:11 | Unzip | Unzip | +| test.cs:160:7:160:12 | Update | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:160:7:160:12 | Update | Update | +| test.cs:161:7:161:18 | UpdateBuffer | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:161:7:161:18 | UpdateBuffer | UpdateBuffer | +| test.cs:162:7:162:24 | UpdateNotification | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:162:7:162:24 | UpdateNotification | UpdateNotification | +| test.cs:163:7:163:29 | UploadSystemDescription | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:163:7:163:29 | UploadSystemDescription | UploadSystemDescription | +| test.cs:164:7:164:11 | Valid | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:164:7:164:11 | Valid | Valid | +| test.cs:165:7:165:17 | WriteConfig | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:165:7:165:17 | WriteConfig | WriteConfig | +| test.cs:166:7:166:15 | WriteFile | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:166:7:166:15 | WriteFile | WriteFile | +| test.cs:167:7:167:23 | WriteReportStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:167:7:167:23 | WriteReportStatus | WriteReportStatus | +| test.cs:168:7:168:24 | WriteServiceStatus | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:168:7:168:24 | WriteServiceStatus | WriteServiceStatus | +| test.cs:169:7:169:9 | Zip | The method $@ may be related to Solorigate. Total count = 104 is above the threshold 50. | test.cs:169:7:169:9 | Zip | Zip | diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qlref b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qlref new file mode 100644 index 00000000000..7483e8f5902 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qlref @@ -0,0 +1 @@ +experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected new file mode 100644 index 00000000000..9125049047e --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.expected @@ -0,0 +1,3 @@ +| test.cs:35:3:38:3 | catch {...} | Empty Swallow Everything Exception. | +| test.cs:289:3:290:4 | catch {...} | Empty Swallow Everything Exception. | +| test.cs:295:3:298:3 | catch (...) {...} | Empty Swallow Everything Exception. | diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qlref b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qlref new file mode 100644 index 00000000000..783fb3f06a0 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qlref @@ -0,0 +1 @@ +experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.ql \ No newline at end of file diff --git a/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs new file mode 100644 index 00000000000..1ee9403a5f1 --- /dev/null +++ b/csharp/ql/test/experimental/Security Features/campaign/Solorigate/test.cs @@ -0,0 +1,309 @@ +using System; +using System.Text; + + +class FalsePositiveCases +{ + // regular FVN + ulong GetRegularFvnHash(string s) + { + ulong num = 14695981039346656037UL; /* FNV base offset */ + + foreach (byte b in Encoding.UTF8.GetBytes(s)) + { + num ^= (ulong)b; + num *= 1099511628211UL; /* FNV prime */ + } + + return num; + } +} + +class TestCases +{ + ulong GetRegularFvnHash(string s) + { + ulong num = 14695981039346656037UL; + try + { + foreach (byte b in Encoding.UTF8.GetBytes(s)) + { + num ^= (ulong)b; + num *= 1099511628211UL; + } + } + catch // BUG : SwallowEverythingExceptionHandler + { + + } + + return num ^ 6605813339339102567UL; // BUG (ModifiedFnvFunctionDetection.ql) + } + + enum JobEngine + { + Idle, + Exit, + SetTime, + CollectSystemDescription, + UploadSystemDescription, + RunTask, + GetProcessByDescription, + KillTask, + GetFileSystemEntries, + WriteFile, + FileExists, + DeleteFile, + GetFileHash, + ReadRegistryValue, + SetRegistryValue, + DeleteRegistryValue, + GetRegistrySubKeyAndValueNames, + Reboot, + None + } + + void Abort() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void AddFileExecutionEngine() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void AddRegistryExecutionEngine() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void AdjustTokenPrivileges() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Base64Decode() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Base64Encode() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ByteArrayToHexString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CheckServerConnection() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Close() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CloseHandle() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CollectSystemDescription() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Compress() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CreateSecureString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CreateString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CreateUploadRequest() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void CreateUploadRequestImpl() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Decompress() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void DecryptShort() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Deflate() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void DelayMin() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void DelayMs() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void DeleteFile() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void DeleteRegistryValue() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void DeleteValue() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ExecuteEngine() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void FileExists() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetAddresses() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetAddressFamily() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetArgumentIndex() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetBaseUri() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetBaseUriImpl() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetCache() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetCurrentProcess() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetCurrentString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetDescriptionId() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetFileHash() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetFileSystemEntries() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetHash() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetHive() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetIntArray() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetIPHostEntry() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetManagementObjectProperty() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetNetworkAdapterConfiguration() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetNewOwnerName() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetNextString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetNextStringEx() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetOrCreateUserID() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetOrionImprovementCustomerId() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetOSVersion() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetPreviousString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetProcessByDescription() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetRegistrySubKeyAndValueNames() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetStatus() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetStringHash() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetSubKeyAndValueNames() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetUserAgent() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetValue() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void GetWebProxy() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void HexStringToByteArray() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Inflate() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Initialize() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void InitiateSystemShutdownExW() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void IsNullOrInvalidName() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void IsSynchronized() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void KillTask() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void LookupPrivilegeValueW() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void OpenProcessToken() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ParseServiceResponse() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Quote() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ReadConfig() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ReadDeviceInfo() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ReadRegistryValue() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ReadReportStatus() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ReadServiceStatus() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void RebootComputer() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void RunTask() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SearchAssemblies() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SearchConfigurations() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SearchServices() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetAutomaticMode() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetKeyOwner() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetKeyOwnerWithPrivileges() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetKeyPermissions() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetManualMode() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetProcessPrivilege() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetRegistryValue() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetTime() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SetValue() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void SplitString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void ToString() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void TrackEvent() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void TrackProcesses() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Unquote() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Unzip() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Update() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void UpdateBuffer() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void UpdateNotification() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void UploadSystemDescription() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Valid() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void WriteConfig() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void WriteFile() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void WriteReportStatus() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void WriteServiceStatus() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + void Zip() { } // BUG : NumberOfKnownMethodNamesAboveThreshold + + void Hashes() { + ulong[] hashes = { // BUG : NumberOfKnownHashesAboveThreshold + 10063651499895178962, 10235971842993272939, 10296494671777307979, + 10336842116636872171, 10374841591685794123, 10393903804869831898, + 10463926208560207521, 10484659978517092504, 10501212300031893463, + 10545868833523019926, 10657751674541025650, 106672141413120087, 10734127004244879770, + 10829648878147112121, 1099511628211, 11073283311104541690, 1109067043404435916, + 11109294216876344399, 11266044540366291518, 11385275378891906608, + 11771945869106552231, 11801746708619571308, 11818825521849580123, + 11913842725949116895, 12027963942392743532, 12094027092655598256, + 12343334044036541897, 12445177985737237804, 12445232961318634374, + 12574535824074203265, 12679195163651834776, 12709986806548166638, + 12718416789200275332, 12785322942775634499, 12790084614253405985, + 12969190449276002545, 13014156621614176974, 13029357933491444455, + 13135068273077306806, 13260224381505715848, 13316211011159594063, + 13464308873961738403, 13544031715334011032, 13581776705111912829, + 13599785766252827703, 13611051401579634621, 13611814135072561278, + 13655261125244647696, 1367627386496056834, 1368907909245890092, 13693525876560827283, + 13783346438774742614, 13799353263187722717, 13825071784440082496, + 13852439084267373191, 13876356431472225791, 14055243717250701608, + 14079676299181301772, 14095938998438966337, 14111374107076822891, + 14193859431895170587, 14226582801651130532, 14243671177281069512, + 14256853800858727521, 14480775929210717493, 14482658293117931546, + 14513577387099045298, 14630721578341374856, 14695981039346656037, + 14710585101020280896, 1475579823244607677, 14868920869169964081, 14968320160131875803, + 14971809093655817917, 15039834196857999838, 15092207615430402812, + 15114163911481793350, 15194901817027173566, 15267980678929160412, + 15457732070353984570, 15514036435533858158, 15535773470978271326, + 15587050164583443069, 155978580751494388, 15695338751700748390, 15997665423159927228, + 16066522799090129502, 16066651430762394116, 16112751343173365533, + 16130138450758310172, 1614465773938842903, 16292685861617888592, 16335643316870329598, + 16423314183614230717, 16570804352575357627, 1682585410644922036, 16858955978146406642, + 16990567851129491937, 17017923349298346219, 17097380490166623672, + 17109238199226571972, 17204844226884380288, 17291806236368054941, + 17351543633914244545, 17439059603042731363, 17574002783607647274, + 17624147599670377042, 17633734304611248415, 17683972236092287897, + 17849680105131524334, 17939405613729073960, 17956969551821596225, + 17978774977754553159, 17984632978012874803, 17997967489723066537, + 18147627057830191163, 18150909006539876521, 18159703063075866524, + 18246404330670877335, 18294908219222222902, 18392881921099771407, + 18446744073709551613, 191060519014405309, 2032008861530788751, 2128122064571842954, + 2147483647, 2147745794, 2380224015317016190, 2478231962306073784, + 2532538262737333146, 2589926981877829912, 2597124982561782591, 2600364143812063535, + 2717025511528702475, 2734787258623754862, 27407921587843457, 2760663353550280147, + 2797129108883749491, 2810460305047003196, 292198192373389586, 2934149816356927366, + 3045986759481489935, 3178468437029279937, 3200333496547938354, 3320026265773918739, + 3320767229281015341, 3341747963119755850, 3407972863931386250, 3413052607651207697, + 3413886037471417852, 3421197789791424393, 3421213182954201407, 3425260965299690882, + 3538022140597504361, 3575761800716667678, 3588624367609827560, 3626142665768487764, + 3642525650883269872, 3656637464651387014, 3660705254426876796, 3769837838875367802, + 3778500091710709090, 3796405623695665524, 3869935012404164040, 3890769468012566366, + 3890794756780010537, 397780960855462669, 4030236413975199654, 4088976323439621041, + 4454255944391929578, 4501656691368064027, 4578480846255629462, 4821863173800309721, + 4931721628717906635, 506634811745884560, 5132256620104998637, 5183687599225757871, + 521157249538507889, 5219431737322569038, 541172992193764396, 5415426428750045503, + 5449730069165757263, 5587557070429522647, 5614586596107908838, 576626207276463000, + 5942282052525294911, 5945487981219695001, 5984963105389676759, 607197993339007484, + 6088115528707848728, 6116246686670134098, 6180361713414290679, 6195833633417633900, + 6274014997237900919, 640589622539783622, 6461429591783621719, 6491986958834001955, + 6508141243778577344, 6605813339339102567, 682250828679635420, 6827032273910657891, + 6943102301517884811, 700598796416086955, 7080175711202577138, 7175363135479931834, + 7315838824213522000, 7412338704062093516, 7516148236133302073, 7574774749059321801, + 7701683279824397773, 7775177810774851294, 7810436520414958497, 7878537243757499832, + 79089792725215063, 7982848972385914508, 8052533790968282297, 8129411991672431889, + 8146185202538899243, 835151375515278827, 8381292265993977266, 8408095252303317471, + 8473756179280619170, 8478833628889826985, 8612208440357175863, 8697424601205169055, + 8698326794961817906, 8709004393777297355, 8727477769544302060, 8760312338504300643, + 8799118153397725683, 8873858923435176895, 8994091295115840290, 9007106680104765185, + 9061219083560670602, 9149947745824492274, 917638920165491138, 9234894663364701749, + 9333057603143916814, 9384605490088500348, 9531326785919727076, 9555688264681862794, + 9559632696372799208, 9903758755917170407 + }; + } + + void Literals() { + string[] literals = { // BUG : NumberOfKnownLiteralsAboveThreshold + "(?i)([^a-z]|^)(test)([^a-z]|$)", "(?i)(solarwinds)", "[{0,5}] {1,-16} {2}\t{3,5} {4}\\{5}\n", + "[{0,5}] {1}\n", "[E] {0} {1} {2}", + "\"\\{[0-9a-f-]{36}\\}\"|\"[0-9a-f]{32}\"|\"[0-9a-f]{16}\"", ".CortexPlugin", ".Orion", + "\"EventName\":\"EventManager\",", "\"EventType\":\"Orion\",", + "\\OrionImprovement\\SolarWinds.OrionImprovement.exe", + "0123456789abcdefghijklmnopqrstuvwxyz-_.", "\"sessionId\":\"{0}\",", "\"steps\":[", + "\"Succeeded\":true,", "\"Timestamp\":\"\\/Date({0})\\/\",", "\"userId\":\"{0}\",", + "{0} {1} HTTP/{2}\n", "10140", "144.86.226.0", "154.118.140.0", "172.16.0.0", "18.130.0.0", + "184.72.0.0", "192.168.0.0", "199.201.117.0", "20.140.0.0", "20100", "20220", "217.163.7.0", + "224.0.0.0", "240.0.0.0", "255.240.0.0", "255.254.0.0", "255.255.248.0", "3.0.0.382", + "41.84.159.0", "43140", "4320", "43260", "524287", "583da945-62af-10e8-4902-a8f205c72b2e", + "65280", "71.152.53.0", "74.114.24.0", "8.18.144.0", "87.238.80.0", "96.31.172.0", "983040", + "99.79.0.0", "Administrator", "advapi32.dll", "Apollo", "appsync-api", "avsvmcloud.com", + "api.solarwinds.com", "-root", "-cert", "-universal_ca", "-ca", "-primary_ca", "-timestamp", + "-global", "-secureca", "CloudMonitoring", "MACAddress", "DHCPEnabled", "DHCPServer", + "DNSHostName", "DNSDomainSuffixSearchOrder", "DNSServerSearchOrder", "IPAddress", "IPSubnet", + "DefaultIPGateway", "OSArchitecture", "InstallDate", "Organization", "RegisteredUser", + "fc00::", "fe00::", "fec0::", "ffc0::", "ff00::", "HKCC", "HKCR", "HKCU", "HKDD", + "HKEY_CLASSES_ROOT", "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA", + "HKEY_LOCAL_MACHINE", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography", + "HKEY_PERFOMANCE_DATA", "HKEY_USERS", "HKLM", "HKPD", "HKU", "If-None-Match", + "Microsoft-CryptoAPI/", "Nodes", "Volumes", "Interfaces", "Components", "opensans", + "Organization", "OSArchitecture", "ParentProcessID", "PathName", "ReportWatcherPostpone", + "ReportWatcherRetry", "S-1-5-", "SeRestorePrivilege", "SeShutdownPrivilege", + "SeTakeOwnershipPrivilege", "SolarWinds", "SolarWindsOrionImprovementClient/", + "SourceCodePro", "SourceHanSans", "SourceHanSerif", "SourceSerifPro", "Start", "swip/Events", + "swip/upd/", "swip/Upload.ashx", "SYSTEM", "SYSTEM\\CurrentControlSet\\services", "us-east-1", + "us-east-2", "us-west-2", "fonts/woff/{0}-{1}-{2}{3}.woff2", + "fonts/woff/{0}-{1}-{2}-webfont{3}.woff2", "ph2eifo3n5utg1j8d94qrvbmk0sal76c", + "pki/crl/{0}{1}{2}.crl", "rq3gsalt6u1iyfzop572d49bnx8cvmkewhj", + "Select * From Win32_NetworkAdapterConfiguration where IPEnabled=true", + "Select * From Win32_OperatingSystem", "Select * From Win32_Process", + "Select * From Win32_SystemDriver", "Select * From Win32_UserAccount" + }; + + } + + void SwallowExceptionTest() + { + try{ + Literals(); + } + catch // BUG : SwallowEverythingExceptionHandler + {} + + try{ + Literals(); + } + catch( Exception e) // BUG : SwallowEverythingExceptionHandler + { + // + } + + try{ + Literals(); + } + catch( Exception e) + { + // NOT A BUG + throw; + } + } +} From 503b339a1f0d121c3976667f4e861908dd52aa15 Mon Sep 17 00:00:00 2001 From: CaptainFreak Date: Tue, 9 Feb 2021 07:35:35 +0530 Subject: [PATCH 248/429] remove hbs specific checks --- .../Security/CWE-073/TemplateObjectInjection.ql | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql index 8c5c19e6096..58c02667af3 100644 --- a/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql +++ b/javascript/ql/src/experimental/Security/CWE-073/TemplateObjectInjection.ql @@ -14,10 +14,6 @@ import javascript import DataFlow::PathGraph import semmle.javascript.security.TaintedObject -predicate isUsingHbsEngine() { - Express::appCreation().getAMethodCall("set").getArgument(1).mayHaveStringValue("hbs") -} - class TemplateObjInjectionConfig extends TaintTracking::Configuration { TemplateObjInjectionConfig() { this = "TemplateObjInjectionConfig" } @@ -32,8 +28,7 @@ class TemplateObjInjectionConfig extends TaintTracking::Configuration { exists(MethodCallExpr mc | Express::isResponse(mc.getReceiver()) and mc.getMethodName() = "render" and - sink.asExpr() = mc.getArgument(1) and - isUsingHbsEngine() + sink.asExpr() = mc.getArgument(1) ) } From 3818971b79d98ae63d01951be5d5fcb26bf783f2 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Tue, 9 Feb 2021 13:09:02 +0100 Subject: [PATCH 249/429] Add redirect sinks Both the familiy of `Accepted` and `Created` method set the location header based on provided input. If this is untrusted input this can result in an URL redirect attack. --- .../code/csharp/frameworks/microsoft/AspNetCore.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll index 3ebd7028504..a00f7d21a05 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/microsoft/AspNetCore.qll @@ -195,7 +195,13 @@ class MicrosoftAspNetCoreMvcController extends Class { /** Gets a `Redirect*` method. */ Method getARedirectMethod() { result = this.getAMethod() and - result.getName().matches("Redirect%") + ( + result.getName().matches("Redirect%") + or + result.getName().matches("Accepted%") + or + result.getName().matches("Created%") + ) } } From 8dd5a7e7c7a11ac645e7fa7c8ad6fb456755eab2 Mon Sep 17 00:00:00 2001 From: alexet Date: Tue, 9 Feb 2021 12:10:09 +0000 Subject: [PATCH 250/429] Javascript Extractor: Update tages to --- .../com/semmle/js/ast/DeclarationFlags.java | 22 +++++++++---------- .../src/com/semmle/js/ast/Literal.java | 2 +- .../com/semmle/js/ast/MemberDefinition.java | 6 ++--- .../com/semmle/js/extractor/ASTExtractor.java | 6 ++--- .../com/semmle/js/extractor/AutoBuild.java | 4 ++-- .../com/semmle/js/extractor/ScopeManager.java | 2 +- .../com/semmle/js/parser/ParsedProject.java | 2 +- .../src/com/semmle/ts/ast/ArrayTypeExpr.java | 2 +- .../semmle/ts/ast/ConditionalTypeExpr.java | 2 +- .../ts/ast/ExportAsNamespaceDeclaration.java | 2 +- .../ts/ast/ExpressionWithTypeArguments.java | 2 +- .../ts/ast/ExternalModuleDeclaration.java | 2 +- .../com/semmle/ts/ast/GenericTypeExpr.java | 2 +- .../ts/ast/GlobalAugmentationDeclaration.java | 2 +- .../com/semmle/ts/ast/INodeWithSymbol.java | 2 +- .../com/semmle/ts/ast/ITypeExpression.java | 2 +- .../src/com/semmle/ts/ast/ImportTypeExpr.java | 2 +- .../semmle/ts/ast/ImportWholeDeclaration.java | 2 +- .../semmle/ts/ast/IndexedAccessTypeExpr.java | 2 +- .../src/com/semmle/ts/ast/InferTypeExpr.java | 2 +- .../com/semmle/ts/ast/InterfaceTypeExpr.java | 2 +- .../semmle/ts/ast/IntersectionTypeExpr.java | 4 ++-- .../com/semmle/ts/ast/KeywordTypeExpr.java | 8 +++---- .../src/com/semmle/ts/ast/MappedTypeExpr.java | 6 ++--- .../com/semmle/ts/ast/NonNullAssertion.java | 2 +- .../com/semmle/ts/ast/OptionalTypeExpr.java | 2 +- .../semmle/ts/ast/ParenthesizedTypeExpr.java | 2 +- .../com/semmle/ts/ast/PredicateTypeExpr.java | 8 +++---- .../src/com/semmle/ts/ast/RestTypeExpr.java | 2 +- .../src/com/semmle/ts/ast/TupleTypeExpr.java | 2 +- .../src/com/semmle/ts/ast/TypeAssertion.java | 2 +- .../src/com/semmle/ts/ast/TypeParameter.java | 6 ++--- .../src/com/semmle/ts/ast/TypeofTypeExpr.java | 2 +- .../src/com/semmle/ts/ast/UnaryTypeExpr.java | 2 +- .../src/com/semmle/ts/ast/UnionTypeExpr.java | 2 +- .../semmle/ts/extractor/TypeExtractor.java | 2 +- .../ts/extractor/TypeScriptASTConverter.java | 16 +++++++------- .../semmle/ts/extractor/TypeScriptParser.java | 4 ++-- .../com/semmle/ts/extractor/TypeTable.java | 4 ++-- 39 files changed, 74 insertions(+), 74 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/ast/DeclarationFlags.java b/javascript/extractor/src/com/semmle/js/ast/DeclarationFlags.java index 28546fdeca8..cbd8b1eedf7 100644 --- a/javascript/extractor/src/com/semmle/js/ast/DeclarationFlags.java +++ b/javascript/extractor/src/com/semmle/js/ast/DeclarationFlags.java @@ -88,59 +88,59 @@ public class DeclarationFlags { return (flags & declareKeyword) != 0; } - /** Returns a mask with the computed bit set to the value of enable. */ + /** Returns a mask with the computed bit set to the value of enable. */ public static int getComputed(boolean enable) { return enable ? computed : 0; } - /** Returns a mask with the abstract bit set to the value of enable. */ + /** Returns a mask with the abstract bit set to the value of enable. */ public static int getAbstract(boolean enable) { return enable ? abstract_ : 0; } - /** Returns a mask with the static bit set to the value of enable. */ + /** Returns a mask with the static bit set to the value of enable. */ public static int getStatic(boolean enable) { return enable ? static_ : 0; } - /** Returns a mask with the public bit set to the value of enable. */ + /** Returns a mask with the public bit set to the value of enable. */ public static int getPublic(boolean enable) { return enable ? public_ : 0; } - /** Returns a mask with the readonly bit set to the value of enable. */ + /** Returns a mask with the readonly bit set to the value of enable. */ public static int getReadonly(boolean enable) { return enable ? readonly : 0; } - /** Returns a mask with the private bit set to the value of enable. */ + /** Returns a mask with the private bit set to the value of enable. */ public static int getPrivate(boolean enable) { return enable ? private_ : 0; } - /** Returns a mask with the protected bit set to the value of enable. */ + /** Returns a mask with the protected bit set to the value of enable. */ public static int getProtected(boolean enable) { return enable ? protected_ : 0; } - /** Returns a mask with the optional bit set to the value of enable. */ + /** Returns a mask with the optional bit set to the value of enable. */ public static int getOptional(boolean enable) { return enable ? optional : 0; } /** - * Returns a mask with the definite assignment assertion bit set to the value of enable. + * Returns a mask with the definite assignment assertion bit set to the value of enable. */ public static int getDefiniteAssignmentAssertion(boolean enable) { return enable ? definiteAssignmentAssertion : 0; } - /** Returns a mask with the declare keyword bit set to the value of enable. */ + /** Returns a mask with the declare keyword bit set to the value of enable. */ public static int getDeclareKeyword(boolean enable) { return enable ? declareKeyword : 0; } - /** Returns true if the nth bit is set in flags. */ + /** Returns true if the nth bit is set in flags. */ public static boolean hasNthFlag(int flags, int n) { return (flags & (1 << n)) != 0; } diff --git a/javascript/extractor/src/com/semmle/js/ast/Literal.java b/javascript/extractor/src/com/semmle/js/ast/Literal.java index 15408b05916..3c53798b851 100644 --- a/javascript/extractor/src/com/semmle/js/ast/Literal.java +++ b/javascript/extractor/src/com/semmle/js/ast/Literal.java @@ -6,7 +6,7 @@ import com.semmle.ts.ast.ITypeExpression; /** * A literal constant. * - *

    A null literal may occur as a TypeScript type annotation - other literals are always + *

    A null literal may occur as a TypeScript type annotation - other literals are always * expressions. */ public class Literal extends Expression implements ITypeExpression { diff --git a/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java b/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java index c04b79fa366..7cacafa96ed 100644 --- a/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java +++ b/javascript/extractor/src/com/semmle/js/ast/MemberDefinition.java @@ -40,7 +40,7 @@ public abstract class MemberDefinition extends Node { return flags; } - /** Returns true if this has the static modifier. */ + /** Returns true if this has the static modifier. */ public boolean isStatic() { return DeclarationFlags.isStatic(flags); } @@ -55,7 +55,7 @@ public abstract class MemberDefinition extends Node { return DeclarationFlags.isAbstract(flags); } - /** Returns true if has the public modifier (not true for implicitly public members). */ + /** Returns true if has the public modifier (not true for implicitly public members). */ public boolean hasPublicKeyword() { return DeclarationFlags.isPublic(flags); } @@ -75,7 +75,7 @@ public abstract class MemberDefinition extends Node { return DeclarationFlags.isReadonly(flags); } - /** Returns true if this has the declare modifier. */ + /** Returns true if this has the declare modifier. */ public boolean hasDeclareKeyword() { return DeclarationFlags.hasDeclareKeyword(flags); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 73cefdae30d..bb270353869 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -253,7 +253,7 @@ public class ASTExtractor { /** * An identifier that refers to a variable from inside a type, i.e. the operand to a - * typeof type or left operand to an is type. + * typeof type or left operand to an is type. * *

    This is generally treated as a type, except a variable binding will be emitted for it. */ @@ -288,7 +288,7 @@ public class ASTExtractor { VAR_AND_TYPE_AND_NAMESPACE_DECL, /** - * An identifier that occurs as part of a named export, such as export { A }. + * An identifier that occurs as part of a named export, such as export { A }. * *

    This may refer to a variable, type, and/or a namespace, and will export exactly those that * can be resolved. @@ -301,7 +301,7 @@ public class ASTExtractor { /** * An identifier that occurs as a qualified name in a default export expression, such as - * A in export default A.B. + * A in export default A.B. * *

    This acts like {@link #EXPORT}, except it cannot refer to a type (i.e. it must be a * variable and/or a namespace). diff --git a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java index 398330acd59..505c45832e2 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java +++ b/javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java @@ -722,13 +722,13 @@ public class AutoBuild { } /** - * Prepares package.json files in a virtual source root, and, if enabled, + * Prepares package.json files in a virtual source root, and, if enabled, * installs dependencies for use by the TypeScript type checker. *

    * Some packages must be downloaded while others exist within the same repo ("monorepos") * but are not in a location where TypeScript would look for it. *

    - * Downloaded packages are intalled under SCRATCH_DIR, in a mirrored directory hierarchy + * Downloaded packages are intalled under SCRATCH_DIR, in a mirrored directory hierarchy * we call the "virtual source root". *

    * Packages that exists within the repo are not downloaded. Since they are part of the main source tree, diff --git a/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java b/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java index 14e88a92c9d..923635037c7 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java @@ -149,7 +149,7 @@ public class ScopeManager { } /** - * Enters a scope for a block of form declare global { ... }. + * Enters a scope for a block of form declare global { ... }. * *

    Declarations in this block will contribute to the global scope, but references can still be * resolved in the scope enclosing the declaration itself. The scope itself does not have its own diff --git a/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java b/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java index 49c6049d452..34315111ba6 100644 --- a/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java +++ b/javascript/extractor/src/com/semmle/js/parser/ParsedProject.java @@ -14,7 +14,7 @@ public class ParsedProject { this.allFiles = allFiles; } - /** Returns the tsconfig.json file that defines this project. */ + /** Returns the tsconfig.json file that defines this project. */ public File getTsConfigFile() { return tsConfigFile; } diff --git a/javascript/extractor/src/com/semmle/ts/ast/ArrayTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/ArrayTypeExpr.java index badcf444439..07a1da74ed7 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ArrayTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ArrayTypeExpr.java @@ -4,7 +4,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; /** - * An array type, such as number[], or in general T[] where T is a type. + * An array type, such as number[], or in general T[] where T is a type. */ public class ArrayTypeExpr extends TypeExpression { private final ITypeExpression elementType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/ConditionalTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/ConditionalTypeExpr.java index 61bc2c647f2..e690f6b6244 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ConditionalTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ConditionalTypeExpr.java @@ -3,7 +3,7 @@ package com.semmle.ts.ast; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** A conditional type annotation, such as T extends any[] ? A : B. */ +/** A conditional type annotation, such as T extends any[] ? A : B. */ public class ConditionalTypeExpr extends TypeExpression { private ITypeExpression checkType; private ITypeExpression extendsType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/ExportAsNamespaceDeclaration.java b/javascript/extractor/src/com/semmle/ts/ast/ExportAsNamespaceDeclaration.java index b6921b34924..f836f052f23 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ExportAsNamespaceDeclaration.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ExportAsNamespaceDeclaration.java @@ -5,7 +5,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Statement; import com.semmle.js.ast.Visitor; -/** A statement of form export as namespace X where X is an identifier. */ +/** A statement of form export as namespace X where X is an identifier. */ public class ExportAsNamespaceDeclaration extends Statement { private Identifier id; diff --git a/javascript/extractor/src/com/semmle/ts/ast/ExpressionWithTypeArguments.java b/javascript/extractor/src/com/semmle/ts/ast/ExpressionWithTypeArguments.java index 4c4c681d078..c1f3c318a9e 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ExpressionWithTypeArguments.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ExpressionWithTypeArguments.java @@ -13,7 +13,7 @@ import java.util.List; * class StringList extends List<string> {} * * - * Above, List is a concrete expression whereas its type argument is a type. + * Above, List is a concrete expression whereas its type argument is a type. */ public class ExpressionWithTypeArguments extends Expression { private final Expression expression; diff --git a/javascript/extractor/src/com/semmle/ts/ast/ExternalModuleDeclaration.java b/javascript/extractor/src/com/semmle/ts/ast/ExternalModuleDeclaration.java index 58baaac7424..555e86da2b4 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ExternalModuleDeclaration.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ExternalModuleDeclaration.java @@ -6,7 +6,7 @@ import com.semmle.js.ast.Statement; import com.semmle.js.ast.Visitor; import java.util.List; -/** A statement of form declare module "X" {...}. */ +/** A statement of form declare module "X" {...}. */ public class ExternalModuleDeclaration extends Statement { private final Literal name; private final List body; diff --git a/javascript/extractor/src/com/semmle/ts/ast/GenericTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/GenericTypeExpr.java index efaee334c1f..1df66ae1fe2 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/GenericTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/GenericTypeExpr.java @@ -4,7 +4,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; import java.util.List; -/** An instantiation of a named type, such as Array<number> */ +/** An instantiation of a named type, such as Array<number> */ public class GenericTypeExpr extends TypeExpression { private final ITypeExpression typeName; // Always Identifier or MemberExpression private final List typeArguments; diff --git a/javascript/extractor/src/com/semmle/ts/ast/GlobalAugmentationDeclaration.java b/javascript/extractor/src/com/semmle/ts/ast/GlobalAugmentationDeclaration.java index b8eec7fac94..008e5e403c1 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/GlobalAugmentationDeclaration.java +++ b/javascript/extractor/src/com/semmle/ts/ast/GlobalAugmentationDeclaration.java @@ -5,7 +5,7 @@ import com.semmle.js.ast.Statement; import com.semmle.js.ast.Visitor; import java.util.List; -/** A statement of form: declare global { ... } */ +/** A statement of form: declare global { ... } */ public class GlobalAugmentationDeclaration extends Statement { private final List body; diff --git a/javascript/extractor/src/com/semmle/ts/ast/INodeWithSymbol.java b/javascript/extractor/src/com/semmle/ts/ast/INodeWithSymbol.java index 9f5e1fe2993..c0fc5864c63 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/INodeWithSymbol.java +++ b/javascript/extractor/src/com/semmle/ts/ast/INodeWithSymbol.java @@ -8,7 +8,7 @@ package com.semmle.ts.ast; */ public interface INodeWithSymbol { /** - * Gets a number identifying the symbol associated with this AST node, or -1 if there is + * Gets a number identifying the symbol associated with this AST node, or -1 if there is * no such symbol. */ int getSymbol(); diff --git a/javascript/extractor/src/com/semmle/ts/ast/ITypeExpression.java b/javascript/extractor/src/com/semmle/ts/ast/ITypeExpression.java index 0054adb4f72..71185a7f92c 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ITypeExpression.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ITypeExpression.java @@ -8,6 +8,6 @@ import com.semmle.js.ast.Literal; * *

    At the QL level, expressions and type annotations are completely separate. In the extractor, * however, some expressions such as {@link Literal} type may occur in a type annotation because the - * TypeScript AST does not distinguish null literals from the null type. + * TypeScript AST does not distinguish null literals from the null type. */ public interface ITypeExpression extends INode, ITypedAstNode {} diff --git a/javascript/extractor/src/com/semmle/ts/ast/ImportTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/ImportTypeExpr.java index edf60004645..11535c3376c 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ImportTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ImportTypeExpr.java @@ -4,7 +4,7 @@ import com.semmle.js.ast.Expression; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** An import type such as in import("http").ServerRequest. */ +/** An import type such as in import("http").ServerRequest. */ public class ImportTypeExpr extends Expression implements ITypeExpression { private final ITypeExpression path; diff --git a/javascript/extractor/src/com/semmle/ts/ast/ImportWholeDeclaration.java b/javascript/extractor/src/com/semmle/ts/ast/ImportWholeDeclaration.java index 4631a615fe2..9b4c7b6b6d8 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ImportWholeDeclaration.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ImportWholeDeclaration.java @@ -6,7 +6,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Statement; import com.semmle.js.ast.Visitor; -/** An import of form import a = E. */ +/** An import of form import a = E. */ public class ImportWholeDeclaration extends Statement { private final Identifier lhs; private final Expression rhs; diff --git a/javascript/extractor/src/com/semmle/ts/ast/IndexedAccessTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/IndexedAccessTypeExpr.java index baf7b95ff2e..420084d3ef2 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/IndexedAccessTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/IndexedAccessTypeExpr.java @@ -3,7 +3,7 @@ package com.semmle.ts.ast; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** A type of form T[K] where T and K are types. */ +/** A type of form T[K] where T and K are types. */ public class IndexedAccessTypeExpr extends TypeExpression { private final ITypeExpression objectType; private final ITypeExpression indexType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/InferTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/InferTypeExpr.java index a18269ce6c2..b9d24409ea6 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/InferTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/InferTypeExpr.java @@ -3,7 +3,7 @@ package com.semmle.ts.ast; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** A type annotation of form infer R */ +/** A type annotation of form infer R */ public class InferTypeExpr extends TypeExpression { private TypeParameter typeParameter; diff --git a/javascript/extractor/src/com/semmle/ts/ast/InterfaceTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/InterfaceTypeExpr.java index 20f2b45b2b8..2c34d0bdb6a 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/InterfaceTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/InterfaceTypeExpr.java @@ -5,7 +5,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; import java.util.List; -/** An inline interface type, such as {x: number; y: number}. */ +/** An inline interface type, such as {x: number; y: number}. */ public class InterfaceTypeExpr extends TypeExpression { private final List> body; diff --git a/javascript/extractor/src/com/semmle/ts/ast/IntersectionTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/IntersectionTypeExpr.java index 2ff10be12cb..820ec752ce7 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/IntersectionTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/IntersectionTypeExpr.java @@ -5,8 +5,8 @@ import com.semmle.js.ast.Visitor; import java.util.List; /** - * An intersection type such as T&S, denoting the intersection of type T and - * type S. + * An intersection type such as T&S, denoting the intersection of type T and + * type S. */ public class IntersectionTypeExpr extends TypeExpression { private final List elementTypes; diff --git a/javascript/extractor/src/com/semmle/ts/ast/KeywordTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/KeywordTypeExpr.java index ede17e079e9..173dfc36294 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/KeywordTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/KeywordTypeExpr.java @@ -4,14 +4,14 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; /** - * One of the TypeScript keyword types, such as string or any. + * One of the TypeScript keyword types, such as string or any. * - *

    This includes the type unique symbol which consists of two keywords but is + *

    This includes the type unique symbol which consists of two keywords but is * represented as a keyword single type expression. * - *

    At the QL level, the null type is also a keyword type. In the extractor, however, + *

    At the QL level, the null type is also a keyword type. In the extractor, however, * this is represented by a Literal, because the TypeScript AST does not distinguish those two uses - * of null. + * of null. */ public class KeywordTypeExpr extends TypeExpression { private final String keyword; diff --git a/javascript/extractor/src/com/semmle/ts/ast/MappedTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/MappedTypeExpr.java index 30129296f34..7c951096bcc 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/MappedTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/MappedTypeExpr.java @@ -4,10 +4,10 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; /** - * A type of form { [K in C]: T }, where T is a type that may refer to K. + * A type of form { [K in C]: T }, where T is a type that may refer to K. * - *

    As with the TypeScript AST, the K in C part is represented as a type parameter with - * C as its upper bound. + *

    As with the TypeScript AST, the K in C part is represented as a type parameter with + * C as its upper bound. */ public class MappedTypeExpr extends TypeExpression { private final TypeParameter typeParameter; diff --git a/javascript/extractor/src/com/semmle/ts/ast/NonNullAssertion.java b/javascript/extractor/src/com/semmle/ts/ast/NonNullAssertion.java index 485b827ce97..6fe3d04b6c8 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/NonNullAssertion.java +++ b/javascript/extractor/src/com/semmle/ts/ast/NonNullAssertion.java @@ -4,7 +4,7 @@ import com.semmle.js.ast.Expression; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** A TypeScript expression of form E!, asserting that E is not null. */ +/** A TypeScript expression of form E!, asserting that E is not null. */ public class NonNullAssertion extends Expression { private final Expression expression; diff --git a/javascript/extractor/src/com/semmle/ts/ast/OptionalTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/OptionalTypeExpr.java index 3d98f563127..b474c8cbaea 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/OptionalTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/OptionalTypeExpr.java @@ -3,7 +3,7 @@ package com.semmle.ts.ast; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** An optional type in a tuple type, such as number? in [string, number?]. */ +/** An optional type in a tuple type, such as number? in [string, number?]. */ public class OptionalTypeExpr extends TypeExpression { private final ITypeExpression elementType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/ParenthesizedTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/ParenthesizedTypeExpr.java index 1be6f191ff7..fd17b9ade0a 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/ParenthesizedTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/ParenthesizedTypeExpr.java @@ -3,7 +3,7 @@ package com.semmle.ts.ast; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** A type expression in parentheses, such as ("foo" | "bar"). */ +/** A type expression in parentheses, such as ("foo" | "bar"). */ public class ParenthesizedTypeExpr extends TypeExpression { private final ITypeExpression elementType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/PredicateTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/PredicateTypeExpr.java index 27bd3c1718c..f0b6042448a 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/PredicateTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/PredicateTypeExpr.java @@ -4,8 +4,8 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; /** - * A type of form E is T, asserts E is T or asserts E where E is - * a parameter name or this and T is a type. + * A type of form E is T, asserts E is T or asserts E where E is + * a parameter name or this and T is a type. */ public class PredicateTypeExpr extends TypeExpression { private final ITypeExpression expression; @@ -23,12 +23,12 @@ public class PredicateTypeExpr extends TypeExpression { this.hasAssertsKeyword = hasAssertsKeyword; } - /** Returns the E in E is T. */ + /** Returns the E in E is T. */ public ITypeExpression getExpression() { return expression; } - /** Returns the T in E is T. */ + /** Returns the T in E is T. */ public ITypeExpression getTypeExpr() { return type; } diff --git a/javascript/extractor/src/com/semmle/ts/ast/RestTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/RestTypeExpr.java index ef0d9ad7f7f..5acb1069ee5 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/RestTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/RestTypeExpr.java @@ -3,7 +3,7 @@ package com.semmle.ts.ast; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; -/** A rest type in a tuple type, such as number[] in [string, ...number[]]. */ +/** A rest type in a tuple type, such as number[] in [string, ...number[]]. */ public class RestTypeExpr extends TypeExpression { private final ITypeExpression arrayType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java index a42df41847e..aa175b59167 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java @@ -5,7 +5,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; import java.util.List; -/** A tuple type, such as [number, string]. */ +/** A tuple type, such as [number, string]. */ public class TupleTypeExpr extends TypeExpression { private final List elementTypes; private final List elementNames; diff --git a/javascript/extractor/src/com/semmle/ts/ast/TypeAssertion.java b/javascript/extractor/src/com/semmle/ts/ast/TypeAssertion.java index 6a9150f93c2..39b108dac79 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/TypeAssertion.java +++ b/javascript/extractor/src/com/semmle/ts/ast/TypeAssertion.java @@ -30,7 +30,7 @@ public class TypeAssertion extends Expression { } /** - * True if this is an assertion of form E as T, as opposed to the old syntax + * True if this is an assertion of form E as T, as opposed to the old syntax * <T> E. */ public boolean isAsExpression() { diff --git a/javascript/extractor/src/com/semmle/ts/ast/TypeParameter.java b/javascript/extractor/src/com/semmle/ts/ast/TypeParameter.java index 7cbf8d2d0eb..c5c516ef2d4 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/TypeParameter.java +++ b/javascript/extractor/src/com/semmle/ts/ast/TypeParameter.java @@ -7,7 +7,7 @@ import com.semmle.js.ast.Visitor; /** * A type parameter declared on a class, interface, function, or type alias. * - *

    The general form of a type parameter is: S extends T = U. + *

    The general form of a type parameter is: S extends T = U. */ public class TypeParameter extends TypeExpression { private final Identifier id; @@ -29,7 +29,7 @@ public class TypeParameter extends TypeExpression { /** * Returns the bound on the type parameter, or {@code null} if there is no bound. * - *

    For example, in T extends Array = number[] the bound is Array. + *

    For example, in T extends Array = number[] the bound is Array. */ public ITypeExpression getBound() { return bound; @@ -38,7 +38,7 @@ public class TypeParameter extends TypeExpression { /** * Returns the type parameter default, or {@code null} if there is no default, * - *

    For example, in T extends Array = number[] the default is number[]. + *

    For example, in T extends Array = number[] the default is number[]. */ public ITypeExpression getDefault() { return default_; diff --git a/javascript/extractor/src/com/semmle/ts/ast/TypeofTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/TypeofTypeExpr.java index cf308191a03..ed56a4c7f9b 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/TypeofTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/TypeofTypeExpr.java @@ -4,7 +4,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; /** - * A type of form typeof E where E is an expression that takes the form of a + * A type of form typeof E where E is an expression that takes the form of a * qualified name. */ public class TypeofTypeExpr extends TypeExpression { diff --git a/javascript/extractor/src/com/semmle/ts/ast/UnaryTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/UnaryTypeExpr.java index 5682bb11d03..66658f27c8e 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/UnaryTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/UnaryTypeExpr.java @@ -6,7 +6,7 @@ import com.semmle.js.ast.Visitor; /** * A unary operator applied to a type. * - *

    This can be keyof T or readonly T. + *

    This can be keyof T or readonly T. */ public class UnaryTypeExpr extends TypeExpression { private final ITypeExpression elementType; diff --git a/javascript/extractor/src/com/semmle/ts/ast/UnionTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/UnionTypeExpr.java index 4be288914f4..fedb0dc5482 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/UnionTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/UnionTypeExpr.java @@ -4,7 +4,7 @@ import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; import java.util.List; -/** A union type such as number | string | boolean. */ +/** A union type such as number | string | boolean. */ public class UnionTypeExpr extends TypeExpression { private final List elementTypes; diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java index caf88175956..08f261b71de 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java @@ -12,7 +12,7 @@ import java.util.Map; /** * Extracts type and symbol information into TRAP files. * - *

    This is closely coupled with the type_table.ts file in the parser-wrapper. Type + *

    This is closely coupled with the type_table.ts file in the parser-wrapper. Type * strings and symbol strings generated in that file are parsed here. See that file for reference * and documentation. */ diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java index 0824ad9be17..36d4f888618 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptASTConverter.java @@ -703,14 +703,14 @@ public class TypeScriptASTConverter { } /** - * Converts the given child to an AST node of the given type or null. A ParseError is + * Converts the given child to an AST node of the given type or null. A ParseError is * thrown if a different type of node was found. * *

    This is used to detect syntax errors that are not reported as syntax errors by the * TypeScript parser. Usually they are reported as errors in a later compiler stage, which the * extractor does not run. * - *

    Returns null if the child is absent. + *

    Returns null if the child is absent. */ @SuppressWarnings("unchecked") private T tryConvertChild(JsonObject node, String prop, Class expectedType) @@ -2515,8 +2515,8 @@ public class TypeScriptASTConverter { } /** - * Returns a specific modifier from the given node (or null if absent), as defined by its - * modifiers property and the kind property of the modifier AST node. + * Returns a specific modifier from the given node (or null if absent), as defined by its + * modifiers property and the kind property of the modifier AST node. */ private JsonObject getModifier(JsonObject node, String modKind) { for (JsonElement mod : getModifiers(node)) @@ -2526,8 +2526,8 @@ public class TypeScriptASTConverter { } /** - * Check whether a node has a particular modifier, as defined by its modifiers property - * and the kind property of the modifier AST node. + * Check whether a node has a particular modifier, as defined by its modifiers property + * and the kind property of the modifier AST node. */ private boolean hasModifier(JsonObject node, String modKind) { return getModifier(node, modKind) != null; @@ -2568,8 +2568,8 @@ public class TypeScriptASTConverter { } /** - * Check whether a node has a particular flag, as defined by its flags property and the - * ts.NodeFlags in enum. + * Check whether a node has a particular flag, as defined by its flags property and the + * ts.NodeFlags in enum. */ private boolean hasFlag(JsonObject node, String flagName) { int flagId = metadata.getNodeFlagId(flagName); diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptParser.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptParser.java index 36792f2d204..70a06656df8 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptParser.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeScriptParser.java @@ -97,7 +97,7 @@ public class TypeScriptParser { public static final String TYPESCRIPT_RETRIES_VAR = "SEMMLE_TYPESCRIPT_RETRIES"; /** - * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be + * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be * set to indicate the maximum heap space usable by the Node.js process, in addition to its * "reserve memory". * @@ -106,7 +106,7 @@ public class TypeScriptParser { public static final String TYPESCRIPT_RAM_SUFFIX = "TYPESCRIPT_RAM"; /** - * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be + * An environment variable (without the SEMMLE_ or LGTM_ prefix), that can be * set to indicate the amount of heap space the Node.js process should reserve for extracting * individual files. * diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeTable.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeTable.java index 0b7e98d0c2a..53d8c437d92 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeTable.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeTable.java @@ -4,9 +4,9 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; /** - * Holds the output of the get-type-table command. + * Holds the output of the get-type-table command. * - *

    See documentation in parser-wrapper/src/type_table.ts. + *

    See documentation in parser-wrapper/src/type_table.ts. */ public class TypeTable { private final JsonArray typeStrings; From d1910a3f5c3deab1ac11bb878546f3c92f760e8b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 9 Feb 2021 12:12:24 +0000 Subject: [PATCH 251/429] Update CONTRIBUTING.md Co-authored-by: Jonas Jensen --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e417a0d9c2..bf7faeaa213 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,7 +49,7 @@ If you have an idea for a query that you would like to share with other CodeQL u - The query must have at least one true positive result on some revision of a real project. -6. **Query Help Files and Unit Tests** +6. **Query help files and unit tests** - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. - see [Supported CodeQL queries and libraries](docs/supported-queries.md) for more information about contributing query help files and unit tests. From eb7e30d472b96a9493ea34996db9ea4ffc4a1a3a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 9 Feb 2021 13:25:12 +0100 Subject: [PATCH 252/429] Python: Add test of django view handler with decorator Which we currently don't handle :( Also added a bit more explanatory comments --- .../frameworks/django-v2-v3/routing_test.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index 9d8c2dedc03..d6736433b0f 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -3,6 +3,7 @@ from django.urls import path, re_path from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseNotFound from django.views import View import django.views.generic.base +from django.views.decorators.http import require_GET def url_match_xss(request, foo, bar, no_taint=None): # $requestHandler routedParameter=foo routedParameter=bar @@ -105,6 +106,10 @@ urlpatterns = [ path("not_valid/", not_valid_identifier), # $routeSetup="not_valid/" ] +################################################################################ +# Deprecated django.conf.urls.url +################################################################################ + # This version 1.x way of defining urls is deprecated in Django 3.1, but still works from django.conf.urls import url @@ -116,9 +121,22 @@ urlpatterns = [ ] +################################################################################ +# Special stuff +################################################################################ + class PossiblyNotRouted(View): # Even if our analysis can't find a route-setup for this class, we should still # consider it to be a handle incoming HTTP requests def get(self, request, possibly_not_routed=42): # $ requestHandler routedParameter=possibly_not_routed return HttpResponse('PossiblyNotRouted get: {}'.format(possibly_not_routed)) # $HttpResponse + + +@require_GET +def with_decorator(request, foo): # $ MISSING: requestHandler routedParameter=foo + pass + +urlpatterns = [ + path("with_decorator/", with_decorator), # $ routeSetup="with_decorator/" +] From 1d25184b3214078361865d579d3c0a6fd63f61e5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 9 Feb 2021 13:35:44 +0100 Subject: [PATCH 253/429] Python: Add test for type-tracking through decorators In general, if there is _some_ decorator on a function, it might not be safe to track content out of it (since the decorator could do anything), but in this case, we can see what the decorator does, so we should be able to handle it (but we don't right now). By my understanding of how type-tracking works, if we track content through `my_decorator`, then we would also track content to the result of `unrelated_func()`, which I wanted to make sure our tests would catch. I found out the core of the problem seems to come from our lack of being able to track to the inner scope, and added an explicit test for that. --- .../dataflow/typetracking/test.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/python/ql/test/experimental/dataflow/typetracking/test.py b/python/ql/test/experimental/dataflow/typetracking/test.py index a4dd1baeac1..4392e3bbf46 100644 --- a/python/ql/test/experimental/dataflow/typetracking/test.py +++ b/python/ql/test/experimental/dataflow/typetracking/test.py @@ -56,6 +56,41 @@ def test_import(): y # $tracked mymodule.z # $tracked + +def to_inner_scope(): + x = tracked # $tracked + def foo(): + y = x # $ MISSING: tracked + return y # $ MISSING: tracked + also_x = foo() # $ MISSING: tracked + print(also_x) # $ MISSING: tracked + + +def my_decorator(func): + # This part doesn't make any sense in a normal decorator, but just shows how we + # handle type-tracking + + func() # $tracked + + def wrapper(): + print("before function call") + val = func() # $ MISSING: tracked + print("after function call") + return val # $ MISSING: tracked + return wrapper + +@my_decorator +def get_tracked2(): + return tracked # $tracked + +@my_decorator +def unrelated_func(): + return "foo" + +def use_funcs_with_decorators(): + x = get_tracked2() # $ MISSING: tracked + y = unrelated_func() + # ------------------------------------------------------------------------------ def expects_int(x): # $int From 9854b95c30ce6161fe811adc21b0699851725c60 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 8 Feb 2021 11:18:56 +0100 Subject: [PATCH 254/429] Fix query performance --- csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql | 10 ++++++++-- csharp/ql/src/Likely Bugs/UncheckedCastInEquals.ql | 8 +++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql b/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql index 3e89dc89e9d..3e71e7c7894 100644 --- a/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql +++ b/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql @@ -27,6 +27,12 @@ class NestedForConditions extends SC::StructuralComparisonConfiguration { } } +private predicate hasChild(Stmt outer, Element child) { + outer = child.getParent() + or + hasChild(outer, child.getParent()) +} + /** A nested `for` statement that shares the same iteration variable as an outer `for` statement. */ class NestedForLoopSameVariable extends ForStmt { ForStmt outer; @@ -35,7 +41,7 @@ class NestedForLoopSameVariable extends ForStmt { MutatorOperation outerUpdate; NestedForLoopSameVariable() { - outer = this.getParent+() and + hasChild(outer, this) and innerUpdate = this.getAnUpdate() and outerUpdate = outer.getAnUpdate() and innerUpdate.getOperand() = iteration.getAnAccess() and @@ -88,7 +94,7 @@ class NestedForLoopSameVariable extends ForStmt { /** Finds elements inside the outer loop that are no longer guarded by the loop invariant. */ private ControlFlow::Node getAnUnguardedNode() { - result.getElement().getParent+() = getOuterForStmt().getBody() and + hasChild(getOuterForStmt().getBody(), result.getElement()) and ( result = this.getCondition().(ControlFlowElement).getAControlFlowExitNode().getAFalseSuccessor() diff --git a/csharp/ql/src/Likely Bugs/UncheckedCastInEquals.ql b/csharp/ql/src/Likely Bugs/UncheckedCastInEquals.ql index 5d2ef55cd1f..7c93d25d646 100644 --- a/csharp/ql/src/Likely Bugs/UncheckedCastInEquals.ql +++ b/csharp/ql/src/Likely Bugs/UncheckedCastInEquals.ql @@ -12,12 +12,18 @@ import csharp import semmle.code.csharp.frameworks.System +private predicate equalsMethodChild(EqualsMethod equals, Element child) { + child = equals + or + equalsMethodChild(equals, child.getParent()) +} + predicate nodeBeforeParameterAccess(ControlFlow::Node node) { exists(EqualsMethod equals | equals.getBody() = node.getElement()) or exists(EqualsMethod equals, Parameter param, ControlFlow::Node mid | equals.getParameter(0) = param and - equals.getAChild*() = mid.getElement() and + equalsMethodChild(equals, mid.getElement()) and nodeBeforeParameterAccess(mid) and not param.getAnAccess() = mid.getElement() and mid.getASuccessor() = node From e194411cfaf4c1a61955ba853ad8fd7984a2ef8b Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Tue, 9 Feb 2021 09:16:57 -0500 Subject: [PATCH 255/429] Java: fix javac errors in test code --- .../security/CWE-273/UnsafeCertTrustTest.java | 10 ++++----- .../security/CWE-297/InsecureJavaMail.java | 4 ++-- .../CWE-312/CleartextStorageSharedPrefs.java | 12 +++++----- .../security/CWE-326/InsufficientKeySize.java | 2 +- .../security/CWE-522/InsecureBasicAuth.java | 12 +++++----- .../security/CWE-522/InsecureLdapAuth.java | 20 ++++++++--------- .../security/CWE-918/SpringSSRF.java | 3 ++- .../library-tests/ExternalProcess/Test.java | 8 +++---- .../library-tests/RelativePaths/Test.java | 2 +- .../commentedcode/CommentedCode.java | 2 +- .../library-tests/dataflow/capture/A.java | 2 +- .../dataflow/taint-ioutils/Test.java | 2 +- .../dataflow/taint-jackson/Test.java | 4 ++-- .../test/library-tests/dataflow/taint/A.java | 12 +++++----- .../test/library-tests/dataflow/taint/B.java | 2 +- .../dataflow/taintsources/IntentSources.java | 10 ++++----- .../dataflow/taintsources/RmiFlow.java | 2 +- .../dataflow/taintsources/RmiFlowImpl.java | 4 ++-- .../dispatch/ViableCallable.java | 20 ++++++++--------- .../dispatch/ViableCallable2.java | 4 ++-- java/ql/test/library-tests/guards/Logic.java | 2 +- java/ql/test/library-tests/guards/Test.java | 2 +- .../pathcreation/PathCreation.java | 14 ++++++------ .../reflection/ReflectiveAccess.java | 2 +- .../successors/TestThrow2/TestThrow2.java | 4 ++-- .../CloseReader/CloseReader.java | 2 +- .../query-tests/ContinueInFalseLoop/A.java | 4 ++-- .../MissingCallToSuperClone/Test.java | 4 ++-- .../MissingInstanceofInEquals/GoodReturn.java | 2 +- java/ql/test/query-tests/Nullness/C.java | 4 ++-- java/ql/test/query-tests/RangeAnalysis/A.java | 4 ++-- .../test/query-tests/UseBraces/UseBraces.java | 14 ++++++------ .../UselessComparisonTest/Test.java | 2 +- .../test/query-tests/UselessNullCheck/A.java | 4 ++-- .../dead-code/DeadField/ReflectionTest.java | 2 +- .../DeadMethod/ReflectionMethodTest.java | 2 +- .../CWE-022/semmle/tests/ZipTest.java | 14 ++++++------ .../query-tests/security/CWE-078/Test.java | 10 ++++----- .../CWE-297/UnsafeHostnameVerification.java | 2 +- .../security/CWE-311/CWE-319/Test.java | 2 +- .../security/CWE-421/semmle/Test.java | 4 ++-- .../test/query-tests/security/CWE-502/A.java | 22 +++++++++---------- .../test/query-tests/security/CWE-502/B.java | 8 +++---- .../CWE-611/DocumentBuilderTests.java | 4 ++-- .../security/CWE-732/semmle/tests/Test.java | 4 ++-- .../semmle/tests/MethodAccessLockOrder.java | 4 ++-- .../android/app/Activity.java | 3 ++- .../android/content/Intent.java | 4 +++- .../android/os/BaseBundle.java | 1 + .../android/os/Parcel.java | 1 + .../crypto/EncryptedSharedPreferences.java | 3 ++- 51 files changed, 149 insertions(+), 142 deletions(-) diff --git a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java index a45727a7406..1e8ecbbc20d 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java +++ b/java/ql/test/experimental/query-tests/security/CWE-273/UnsafeCertTrustTest.java @@ -87,7 +87,7 @@ public class UnsafeCertTrustTest { /** * Test the endpoint identification of SSL engine is set to null */ - public void testSSLEngineEndpointIdSetNull() { + public void testSSLEngineEndpointIdSetNull() throws java.security.NoSuchAlgorithmException { SSLContext sslContext = SSLContext.getInstance("TLS"); SSLEngine sslEngine = sslContext.createSSLEngine(); SSLParameters sslParameters = sslEngine.getSSLParameters(); @@ -98,7 +98,7 @@ public class UnsafeCertTrustTest { /** * Test the endpoint identification of SSL engine is not set */ - public void testSSLEngineEndpointIdNotSet() { + public void testSSLEngineEndpointIdNotSet() throws java.security.NoSuchAlgorithmException { SSLContext sslContext = SSLContext.getInstance("TLS"); SSLEngine sslEngine = sslContext.createSSLEngine(); } @@ -106,7 +106,7 @@ public class UnsafeCertTrustTest { /** * Test the endpoint identification of SSL socket is not set */ - public void testSSLSocketEndpointIdNotSet() { + public void testSSLSocketEndpointIdNotSet() throws java.security.NoSuchAlgorithmException, java.io.IOException { SSLContext sslContext = SSLContext.getInstance("TLS"); final SSLSocketFactory socketFactory = sslContext.getSocketFactory(); SSLSocket socket = (SSLSocket) socketFactory.createSocket("www.example.com", 443); @@ -115,7 +115,7 @@ public class UnsafeCertTrustTest { /** * Test the endpoint identification of regular socket is not set */ - public void testSocketEndpointIdNotSet() { + public void testSocketEndpointIdNotSet() throws java.io.IOException { SocketFactory socketFactory = SocketFactory.getDefault(); Socket socket = socketFactory.createSocket("www.example.com", 80); } @@ -127,4 +127,4 @@ public class UnsafeCertTrustTest { // ConnectionFactory connectionFactory = new ConnectionFactory(); // connectionFactory.useSslProtocol(); // } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java index 05d700437dd..62c64027695 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java +++ b/java/ql/test/experimental/query-tests/security/CWE-297/InsecureJavaMail.java @@ -29,7 +29,7 @@ class InsecureJavaMail { final Session session = Session.getInstance(properties, authenticator); } - public void testSimpleMail() { + public void testSimpleMail() throws Exception { Email email = new SimpleEmail(); email.setHostName("config.hostName"); email.setSmtpPort(25); @@ -42,4 +42,4 @@ class InsecureJavaMail { email.addTo("toAddress"); email.send(); } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-312/CleartextStorageSharedPrefs.java b/java/ql/test/experimental/query-tests/security/CWE-312/CleartextStorageSharedPrefs.java index 51a92314c67..39614c82234 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-312/CleartextStorageSharedPrefs.java +++ b/java/ql/test/experimental/query-tests/security/CWE-312/CleartextStorageSharedPrefs.java @@ -20,7 +20,7 @@ public class CleartextStorageSharedPrefs extends Activity { } // GOOD - save sensitive information in encrypted format - public void testSetSharedPrefs2(Context context, String name, String password) { + public void testSetSharedPrefs2(Context context, String name, String password) throws Exception { SharedPreferences sharedPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE); Editor editor = sharedPrefs.edit(); editor.putString("name", encrypt(name)); @@ -28,7 +28,7 @@ public class CleartextStorageSharedPrefs extends Activity { editor.commit(); } - private static String encrypt(String cleartext) { + private static String encrypt(String cleartext) throws Exception { // Use an encryption or hashing algorithm in real world. The demo below just returns its hash. MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(cleartext.getBytes(StandardCharsets.UTF_8)); @@ -37,7 +37,7 @@ public class CleartextStorageSharedPrefs extends Activity { } // GOOD - save sensitive information in encrypted format using separate variables - public void testSetSharedPrefs3(Context context, String name, String password) { + public void testSetSharedPrefs3(Context context, String name, String password) throws Exception { String encUsername = encrypt(name); String encPassword = encrypt(password); SharedPreferences sharedPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE); @@ -49,7 +49,7 @@ public class CleartextStorageSharedPrefs extends Activity { // GOOD - save sensitive information using the built-in `EncryptedSharedPreferences` class in androidx - public void testSetSharedPrefs4(Context context, String name, String password) { + public void testSetSharedPrefs4(Context context, String name, String password) throws Exception { MasterKey masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); @@ -69,7 +69,7 @@ public class CleartextStorageSharedPrefs extends Activity { } // GOOD - save sensitive information using the built-in `EncryptedSharedPreferences` class in androidx - public void testSetSharedPrefs5(Context context, String name, String password) { + public void testSetSharedPrefs5(Context context, String name, String password) throws Exception { MasterKey masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); @@ -89,7 +89,7 @@ public class CleartextStorageSharedPrefs extends Activity { } // GOOD - save sensitive information using the built-in `EncryptedSharedPreferences` class in androidx - public void testSetSharedPrefs6(Context context, String name, String password) { + public void testSetSharedPrefs6(Context context, String name, String password) throws Exception { MasterKey masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build(); diff --git a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java index df46d6e69a9..a606017a27e 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java +++ b/java/ql/test/experimental/query-tests/security/CWE-326/InsufficientKeySize.java @@ -3,7 +3,7 @@ import java.security.spec.ECGenParameterSpec; import javax.crypto.KeyGenerator; public class InsufficientKeySize { - public void CryptoMethod() { + public void CryptoMethod() throws java.security.NoSuchAlgorithmException, java.security.InvalidAlgorithmParameterException { KeyGenerator keyGen1 = KeyGenerator.getInstance("AES"); // BAD: Key size is less than 128 keyGen1.init(64); diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.java b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.java index 1f7be303471..c59af48e09b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.java +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureBasicAuth.java @@ -57,7 +57,7 @@ public class InsecureBasicAuth { /** * Test basic authentication with Apache HTTP POST request using the URI constructor with one argument. */ - public void testApacheHttpRequest4(String username, String password) { + public void testApacheHttpRequest4(String username, String password) throws Exception { String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; URI uri = new URI(uriStr); HttpRequestBase post = new HttpPost(uri); @@ -74,7 +74,7 @@ public class InsecureBasicAuth { /** * Test basic authentication with Apache HTTP POST request using a URI constructor with multiple arguments. */ - public void testApacheHttpRequest5(String username, String password) { + public void testApacheHttpRequest5(String username, String password) throws Exception { HttpRequestBase post = new HttpPost(new URI("http", "www.example.com", "/test", "abc=123", null)); post.setHeader("Accept", "application/json"); post.setHeader("Content-type", "application/json"); @@ -122,7 +122,7 @@ public class InsecureBasicAuth { /** * Test basic authentication with Java HTTP URL connection using the `URL(String spec)` constructor. */ - public void testHttpUrlConnection(String username, String password) { + public void testHttpUrlConnection(String username, String password) throws Exception { String urlStr = "http://www.example.com/rest/getuser.do?uid=abcdx"; String authString = username + ":" + password; String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8")); @@ -136,7 +136,7 @@ public class InsecureBasicAuth { /** * Test basic authentication with Java HTTP URL connection using the `URL(String protocol, String host, String file)` constructor. */ - public void testHttpUrlConnection2(String username, String password) { + public void testHttpUrlConnection2(String username, String password) throws Exception { String host = "www.example.com"; String path = "/rest/getuser.do?uid=abcdx"; String protocol = "http"; @@ -152,7 +152,7 @@ public class InsecureBasicAuth { /** * Test basic authentication with Java HTTP URL connection using a constructor with private URL. */ - public void testHttpUrlConnection3(String username, String password) { + public void testHttpUrlConnection3(String username, String password) throws Exception { String host = "LOCALHOST"; String authString = username + ":" + password; String encoding = Base64.getEncoder().encodeToString(authString.getBytes("UTF-8")); @@ -161,4 +161,4 @@ public class InsecureBasicAuth { conn.setDoOutput(true); conn.setRequestProperty("Authorization", "Basic " + encoding); } -} \ No newline at end of file +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java index 14142d31b21..978a4df671b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java +++ b/java/ql/test/experimental/query-tests/security/CWE-522/InsecureLdapAuth.java @@ -7,7 +7,7 @@ import javax.naming.ldap.InitialLdapContext; public class InsecureLdapAuth { // BAD - Test LDAP authentication in cleartext using `DirContext`. - public void testCleartextLdapAuth(String ldapUserName, String password) { + public void testCleartextLdapAuth(String ldapUserName, String password) throws Exception { String ldapUrl = "ldap://ad.your-server.com:389"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -21,7 +21,7 @@ public class InsecureLdapAuth { } // BAD - Test LDAP authentication in cleartext using `DirContext`. - public void testCleartextLdapAuth(String ldapUserName, String password, String serverName) { + public void testCleartextLdapAuth(String ldapUserName, String password, String serverName) throws Exception { String ldapUrl = "ldap://"+serverName+":389"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -35,7 +35,7 @@ public class InsecureLdapAuth { } // GOOD - Test LDAP authentication over SSL. - public void testSslLdapAuth(String ldapUserName, String password) { + public void testSslLdapAuth(String ldapUserName, String password) throws Exception { String ldapUrl = "ldaps://ad.your-server.com:636"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -49,7 +49,7 @@ public class InsecureLdapAuth { } // GOOD - Test LDAP authentication over SSL. - public void testSslLdapAuth2(String ldapUserName, String password) { + public void testSslLdapAuth2(String ldapUserName, String password) throws Exception { String ldapUrl = "ldap://ad.your-server.com:636"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -64,7 +64,7 @@ public class InsecureLdapAuth { } // GOOD - Test LDAP authentication with SASL authentication. - public void testSaslLdapAuth(String ldapUserName, String password) { + public void testSaslLdapAuth(String ldapUserName, String password) throws Exception { String ldapUrl = "ldap://ad.your-server.com:389"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -78,7 +78,7 @@ public class InsecureLdapAuth { } // GOOD - Test LDAP authentication in cleartext connecting to local LDAP server. - public void testCleartextLdapAuth2(String ldapUserName, String password) { + public void testCleartextLdapAuth2(String ldapUserName, String password) throws Exception { String ldapUrl = "ldap://localhost:389"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -92,7 +92,7 @@ public class InsecureLdapAuth { } // BAD - Test LDAP authentication in cleartext using `InitialLdapContext`. - public void testCleartextLdapAuth3(String ldapUserName, String password) { + public void testCleartextLdapAuth3(String ldapUserName, String password) throws Exception { String ldapUrl = "ldap://ad.your-server.com:389"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, @@ -107,7 +107,7 @@ public class InsecureLdapAuth { // BAD - Test LDAP authentication in cleartext using `DirContext` and string literals. - public void testCleartextLdapAuth4(String ldapUserName, String password) { + public void testCleartextLdapAuth4(String ldapUserName, String password) throws Exception { String ldapUrl = "ldap://ad.your-server.com:389"; Hashtable environment = new Hashtable(); environment.put("java.naming.factory.initial", @@ -131,7 +131,7 @@ public class InsecureLdapAuth { } // GOOD - Test LDAP authentication with `ssl` configuration and basic authentication. - public void testCleartextLdapAuth5(String ldapUserName, String password, String serverName) { + public void testCleartextLdapAuth5(String ldapUserName, String password, String serverName) throws Exception { String ldapUrl = "ldap://"+serverName+":389"; Hashtable environment = new Hashtable(); setSSL(environment); @@ -143,7 +143,7 @@ public class InsecureLdapAuth { } // BAD - Test LDAP authentication with basic authentication. - public void testCleartextLdapAuth6(String ldapUserName, String password, String serverName) { + public void testCleartextLdapAuth6(String ldapUserName, String password, String serverName) throws Exception { String ldapUrl = "ldap://"+serverName+":389"; Hashtable environment = new Hashtable(); environment.put(Context.INITIAL_CONTEXT_FACTORY, diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java b/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java index ddd8ecc3dd6..a7d3cb32b87 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java +++ b/java/ql/test/experimental/query-tests/security/CWE-918/SpringSSRF.java @@ -26,7 +26,7 @@ public class SpringSSRF extends HttpServlet { String fooResourceUrl = request2.getParameter("uri");; RestTemplate restTemplate = new RestTemplate(); HttpEntity request = new HttpEntity<>(new String("bar")); - + try { { ResponseEntity response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class); @@ -68,5 +68,6 @@ public class SpringSSRF extends HttpServlet { { restTemplate.put(fooResourceUrl, new String("object")); } + } catch (org.springframework.web.client.RestClientException | java.net.URISyntaxException e) {} } } diff --git a/java/ql/test/library-tests/ExternalProcess/Test.java b/java/ql/test/library-tests/ExternalProcess/Test.java index c3554589282..ee29327ef90 100644 --- a/java/ql/test/library-tests/ExternalProcess/Test.java +++ b/java/ql/test/library-tests/ExternalProcess/Test.java @@ -43,28 +43,28 @@ class Test { new Bogus().exec("Irrelevant version of exec"); } - void apacheExecute1() { + void apacheExecute1() throws IOException { String line = "AcroRd32.exe /p /h some.file"; CommandLine cmdLine = CommandLine.parse(line); DefaultExecutor executor = new DefaultExecutor(); int exitValue = executor.execute(cmdLine); } - void apacheExecute2() { + void apacheExecute2() throws IOException { String line = "AcroRd32.exe /p /h some.file"; CommandLine cmdLine = CommandLine.parse(line, null); DefaultExecutor executor = new DefaultExecutor(); int exitValue = executor.execute(cmdLine); } - void apacheExecute3() { + void apacheExecute3() throws IOException { CommandLine cmdLine = new CommandLine("AcroRd32.exe"); cmdLine.addArguments("/p /h some.file"); DefaultExecutor executor = new DefaultExecutor(); int exitValue = executor.execute(cmdLine); } - void apacheExecute4() { + void apacheExecute4() throws IOException { CommandLine cmdLine = new CommandLine("AcroRd32.exe"); cmdLine.addArguments("/p /h some.file", false); DefaultExecutor executor = new DefaultExecutor(); diff --git a/java/ql/test/library-tests/RelativePaths/Test.java b/java/ql/test/library-tests/RelativePaths/Test.java index 860b7ffbecf..4c020819121 100644 --- a/java/ql/test/library-tests/RelativePaths/Test.java +++ b/java/ql/test/library-tests/RelativePaths/Test.java @@ -1,5 +1,5 @@ class Test { - public static void main(String[] args) { + public static void main(String[] args) throws java.io.IOException { // Relative paths Runtime.getRuntime().exec("make"); Runtime.getRuntime().exec("m"); diff --git a/java/ql/test/library-tests/commentedcode/CommentedCode.java b/java/ql/test/library-tests/commentedcode/CommentedCode.java index fa14ad7cc69..02bee2fe2f9 100644 --- a/java/ql/test/library-tests/commentedcode/CommentedCode.java +++ b/java/ql/test/library-tests/commentedcode/CommentedCode.java @@ -88,8 +88,8 @@ public class CommentedCode { *   ; *   ; */ + return -1; } - // public static int commentedOutMethod(){ // // return 123; diff --git a/java/ql/test/library-tests/dataflow/capture/A.java b/java/ql/test/library-tests/dataflow/capture/A.java index 2311179499a..8bc40f9ae77 100644 --- a/java/ql/test/library-tests/dataflow/capture/A.java +++ b/java/ql/test/library-tests/dataflow/capture/A.java @@ -32,7 +32,7 @@ public class A { case 0: return p; case 1: return s; case 2: return b1.getElem(); - case 3: return b2.getElem(); + default:return b2.getElem(); } } }; diff --git a/java/ql/test/library-tests/dataflow/taint-ioutils/Test.java b/java/ql/test/library-tests/dataflow/taint-ioutils/Test.java index 1d616184705..a6660c87252 100644 --- a/java/ql/test/library-tests/dataflow/taint-ioutils/Test.java +++ b/java/ql/test/library-tests/dataflow/taint-ioutils/Test.java @@ -8,7 +8,7 @@ import java.util.List; import org.apache.commons.io.IOUtils; class Test { - public static void ioutils() { + public static void ioutils() throws java.io.FileNotFoundException, java.io.IOException { InputStream inp = new FileInputStream("test"); // user input InputStream buf = IOUtils.buffer(inp); diff --git a/java/ql/test/library-tests/dataflow/taint-jackson/Test.java b/java/ql/test/library-tests/dataflow/taint-jackson/Test.java index 6c3a7dbf4b5..2caf9e4ee80 100644 --- a/java/ql/test/library-tests/dataflow/taint-jackson/Test.java +++ b/java/ql/test/library-tests/dataflow/taint-jackson/Test.java @@ -14,7 +14,7 @@ class Test { return "tainted"; } - public static void jacksonObjectMapper() { + public static void jacksonObjectMapper() throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { String s = taint(); ObjectMapper om = new ObjectMapper(); File file = new File("testFile"); @@ -32,7 +32,7 @@ class Test { System.out.println(reconstructed); } - public static void jacksonObjectWriter() { + public static void jacksonObjectWriter() throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { String s = taint(); ObjectWriter ow = new ObjectWriter(); File file = new File("testFile"); diff --git a/java/ql/test/library-tests/dataflow/taint/A.java b/java/ql/test/library-tests/dataflow/taint/A.java index e3a38d8e191..55fd9796586 100644 --- a/java/ql/test/library-tests/dataflow/taint/A.java +++ b/java/ql/test/library-tests/dataflow/taint/A.java @@ -15,7 +15,7 @@ public class A { sink(b2); } - void test2() { + void test2() throws IOException { ByteArrayOutputStream bOutput = new ByteArrayOutputStream(); bOutput.write(taint()); byte[] b = bOutput.toByteArray(); @@ -25,11 +25,11 @@ public class A { sink(b2); } - void streamWrite(ByteArrayOutputStream baos, byte[] data) { + void streamWrite(ByteArrayOutputStream baos, byte[] data) throws IOException { baos.write(data); } - void test3(ByteArrayOutputStream baos) { + void test3(ByteArrayOutputStream baos) throws IOException { streamWrite(baos, taint()); sink(baos.toByteArray()); } @@ -38,11 +38,11 @@ public class A { ByteArrayOutputStream baos = new ByteArrayOutputStream(); } - void streamWriteHolder(BaosHolder bh, byte[] data) { + void streamWriteHolder(BaosHolder bh, byte[] data) throws IOException { bh.baos.write(data); } - void test4(BaosHolder bh) { + void test4(BaosHolder bh) throws IOException { streamWriteHolder(bh, taint()); sink(bh.baos.toByteArray()); } @@ -51,7 +51,7 @@ public class A { byte[] data = new byte[10]; } - void test5_a(DataHolder dh) { + void test5_a(DataHolder dh) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(taint()); bais.read(dh.data); test5_b(dh); diff --git a/java/ql/test/library-tests/dataflow/taint/B.java b/java/ql/test/library-tests/dataflow/taint/B.java index b53c49bdc39..81b007e6871 100644 --- a/java/ql/test/library-tests/dataflow/taint/B.java +++ b/java/ql/test/library-tests/dataflow/taint/B.java @@ -11,7 +11,7 @@ public class B { public static void sink(Object o) { } - public static void maintest() { + public static void maintest() throws java.io.UnsupportedEncodingException, java.net.MalformedURLException { String[] args = taint(); // tainted - access to main args String[] aaaargs = args; diff --git a/java/ql/test/library-tests/dataflow/taintsources/IntentSources.java b/java/ql/test/library-tests/dataflow/taintsources/IntentSources.java index 960bbff0bce..6f0051f0d10 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/IntentSources.java +++ b/java/ql/test/library-tests/dataflow/taintsources/IntentSources.java @@ -4,21 +4,21 @@ import android.app.Activity; public class IntentSources extends Activity { - public void test() { + public void test() throws java.io.IOException { String trouble = this.getIntent().getStringExtra("key"); Runtime.getRuntime().exec(trouble); } - public void test2() { + public void test2() throws java.io.IOException { String trouble = getIntent().getStringExtra("key"); Runtime.getRuntime().exec(trouble); } - public void test3() { + public void test3() throws java.io.IOException { String trouble = getIntent().getExtras().getString("key"); Runtime.getRuntime().exec(trouble); @@ -29,9 +29,9 @@ public class IntentSources extends Activity { class OtherClass { - public void test(IntentSources is) { + public void test(IntentSources is) throws java.io.IOException { String trouble = is.getIntent().getStringExtra("key"); Runtime.getRuntime().exec(trouble); } -} \ No newline at end of file +} diff --git a/java/ql/test/library-tests/dataflow/taintsources/RmiFlow.java b/java/ql/test/library-tests/dataflow/taintsources/RmiFlow.java index eeab5a1fa09..69d7c9449ee 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/RmiFlow.java +++ b/java/ql/test/library-tests/dataflow/taintsources/RmiFlow.java @@ -4,5 +4,5 @@ import java.rmi.Remote; import java.rmi.RemoteException; public interface RmiFlow extends Remote { - String listDirectory(String path); + String listDirectory(String path) throws java.io.IOException; } diff --git a/java/ql/test/library-tests/dataflow/taintsources/RmiFlowImpl.java b/java/ql/test/library-tests/dataflow/taintsources/RmiFlowImpl.java index eee65d5c64e..f75c6ddf2b7 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/RmiFlowImpl.java +++ b/java/ql/test/library-tests/dataflow/taintsources/RmiFlowImpl.java @@ -1,13 +1,13 @@ package security.library.dataflow; public class RmiFlowImpl implements RmiFlow { - public String listDirectory(String path) { + public String listDirectory(String path) throws java.io.IOException { String command = "ls " + path; Runtime.getRuntime().exec(command); return "pretend there are some results here"; } - public String notRemotable(String path) { + public String notRemotable(String path) throws java.io.IOException { String command = "ls " + path; Runtime.getRuntime().exec(command); return "pretend there are some results here"; diff --git a/java/ql/test/library-tests/dispatch/ViableCallable.java b/java/ql/test/library-tests/dispatch/ViableCallable.java index 1e404463c05..f698ea0fb9d 100644 --- a/java/ql/test/library-tests/dispatch/ViableCallable.java +++ b/java/ql/test/library-tests/dispatch/ViableCallable.java @@ -36,7 +36,7 @@ class ViableCallable { i2.f("", 0l); } - TMock Mock() { throw new Exception(); } + TMock Mock() { throw new Error(); } void CreateTypeInstance() { Run(new C2(), null, null, null); @@ -63,7 +63,7 @@ abstract class C1 { M(x, 8); } - public void f(T1_C1 x, T2_C1 y) { throw new Exception(); } + public void f(T1_C1 x, T2_C1 y) { throw new Error(); } } interface I1 { @@ -80,27 +80,27 @@ interface I2 { class C2 extends C1 implements I1 { @Override - public T_C2 M(String x, T3_C2 y) { throw new Exception(); } + public T_C2 M(String x, T3_C2 y) { throw new Error(); } } class C3 extends C1 implements I2 { @Override - public Long M(String x, T3_C3 y) { throw new Exception(); } + public Long M(String x, T3_C3 y) { throw new Error(); } } class C4 extends C1 { @Override - public Boolean M(T_C4[] x, T3_C4 y) { throw new Exception(); } + public Boolean M(T_C4[] x, T3_C4 y) { throw new Error(); } } class C5 extends C1 { @Override - public Boolean M(String x, T3_C5 y) { throw new Exception(); } + public Boolean M(String x, T3_C5 y) { throw new Error(); } } class C6 extends C1 { @Override - public T2_C6 M(T1_C6 x, T3_C6 y) { throw new Exception(); } + public T2_C6 M(T1_C6 x, T3_C6 y) { throw new Error(); } public void Run(T1_C6 x) { // Viable callables: C6.M(), C7.M() @@ -113,7 +113,7 @@ class C6 extends C1 { class C7 extends C6 { @Override - public Byte M(T1_C7 x, T3_C7 y) { throw new Exception(); } + public Byte M(T1_C7 x, T3_C7 y) { throw new Error(); } public void Run(T1_C7 x) { // Viable callables: C7.M() @@ -129,11 +129,11 @@ class C7 extends C6 { class C8 extends C1 { @Override - public T2_C8 M(String x, T3_C8 y) { throw new Exception(); } + public T2_C8 M(String x, T3_C8 y) { throw new Error(); } } class C9 extends C8 { @Override - public Boolean M(String x, T3_C9 y) { throw new Exception(); } + public Boolean M(String x, T3_C9 y) { throw new Error(); } } diff --git a/java/ql/test/library-tests/dispatch/ViableCallable2.java b/java/ql/test/library-tests/dispatch/ViableCallable2.java index a1d17b63162..79ecc9d3cd0 100644 --- a/java/ql/test/library-tests/dispatch/ViableCallable2.java +++ b/java/ql/test/library-tests/dispatch/ViableCallable2.java @@ -20,10 +20,10 @@ class ViableCallable2 { } class A { - public void m() { throw new Exception(); } + public void m() { throw new Error(); } } class B extends A { @Override - public void m() { throw new Exception(); } + public void m() { throw new Error(); } } diff --git a/java/ql/test/library-tests/guards/Logic.java b/java/ql/test/library-tests/guards/Logic.java index a07890a4a75..afe646908a0 100644 --- a/java/ql/test/library-tests/guards/Logic.java +++ b/java/ql/test/library-tests/guards/Logic.java @@ -41,7 +41,7 @@ public class Logic { } private static void checkTrue(boolean b, String msg) { - if (!b) throw new Exception(msg); + if (!b) throw new Error (msg); } private static void checkFalse(boolean b, String msg) { diff --git a/java/ql/test/library-tests/guards/Test.java b/java/ql/test/library-tests/guards/Test.java index 59f63917b09..d4441f98fdd 100644 --- a/java/ql/test/library-tests/guards/Test.java +++ b/java/ql/test/library-tests/guards/Test.java @@ -3,7 +3,7 @@ class Test { void test(int x) { z = 0; if (x < 0) { - throw new Exception(); + throw new Error(); } int y = 0; while(x >= 0) { diff --git a/java/ql/test/library-tests/pathcreation/PathCreation.java b/java/ql/test/library-tests/pathcreation/PathCreation.java index dcdb28adf45..fcd1eed3e28 100644 --- a/java/ql/test/library-tests/pathcreation/PathCreation.java +++ b/java/ql/test/library-tests/pathcreation/PathCreation.java @@ -18,7 +18,7 @@ class PathCreation { File f = new File(new File("dir"), "sub"); } - public void testNewFileWithURI() { + public void testNewFileWithURI() throws java.net.URISyntaxException { File f = new File(new URI("dir")); } @@ -27,7 +27,7 @@ class PathCreation { Path p2 = Path.of("dir", "sub"); } - public void testPathOfWithURI() { + public void testPathOfWithURI() throws java.net.URISyntaxException { Path p = Path.of(new URI("dir")); } @@ -36,7 +36,7 @@ class PathCreation { Path p2 = Paths.get("dir", "sub"); } - public void testPathsGetWithURI() { + public void testPathsGetWithURI() throws java.net.URISyntaxException { Path p = Paths.get(new URI("dir")); } @@ -53,19 +53,19 @@ class PathCreation { Path p = Path.of("dir").resolve("sub"); } - public void testNewFileWriterWithString() { + public void testNewFileWriterWithString() throws java.io.IOException { FileWriter fw = new FileWriter("dir"); } - public void testNewFileReaderWithString() { + public void testNewFileReaderWithString() throws java.io.FileNotFoundException { FileReader fr = new FileReader("dir"); } - public void testNewFileOutputStreamWithString() { + public void testNewFileOutputStreamWithString() throws java.io.FileNotFoundException { FileOutputStream fos = new FileOutputStream("dir"); } - public void testNewFileInputStreamWithString() { + public void testNewFileInputStreamWithString() throws java.io.FileNotFoundException { FileInputStream fis = new FileInputStream("dir"); } } diff --git a/java/ql/test/library-tests/reflection/reflection/ReflectiveAccess.java b/java/ql/test/library-tests/reflection/reflection/ReflectiveAccess.java index 2a729af39fd..99687ea2649 100644 --- a/java/ql/test/library-tests/reflection/reflection/ReflectiveAccess.java +++ b/java/ql/test/library-tests/reflection/reflection/ReflectiveAccess.java @@ -14,7 +14,7 @@ public class ReflectiveAccess { return classContainingAnnotation.getAnnotation(annotationClass); } - public static void main(String[] args) { + public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class testClass = Class.forName("reflection.ReflectiveAccess$TestClass"); testClass.newInstance(); diff --git a/java/ql/test/library-tests/successors/TestThrow2/TestThrow2.java b/java/ql/test/library-tests/successors/TestThrow2/TestThrow2.java index c3652aa161c..29f86a7bb58 100644 --- a/java/ql/test/library-tests/successors/TestThrow2/TestThrow2.java +++ b/java/ql/test/library-tests/successors/TestThrow2/TestThrow2.java @@ -5,8 +5,8 @@ class TestThrow2 { { try { thrower(); - } catch (Exception e) { + } catch (Throwable e) { ; } } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java b/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java index 38549f5873c..7d78f8dbfef 100644 --- a/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java +++ b/java/ql/test/query-tests/CloseResource/CloseReader/CloseReader.java @@ -100,7 +100,7 @@ class CloseReader { private void init(InputStreamReader reader) { fileRd = new BufferedReader(reader); } - public void readStuff() { + public void readStuff() throws java.io.IOException { System.out.println(fileRd.readLine()); fileRd.close(); } diff --git a/java/ql/test/query-tests/ContinueInFalseLoop/A.java b/java/ql/test/query-tests/ContinueInFalseLoop/A.java index 14c4ee0e7aa..911d4146a66 100644 --- a/java/ql/test/query-tests/ContinueInFalseLoop/A.java +++ b/java/ql/test/query-tests/ContinueInFalseLoop/A.java @@ -32,14 +32,14 @@ public class A { // --- while, for loops --- - while (false) { + while (c.cond()) { if (c.cond()) continue; // GOOD [never reached, if the condition changed so it was then the result would no longer apply] if (c.cond()) break; } - for (i = 0; false; i++) { + for (i = 0; c.cond(); i++) { if (c.cond()) continue; // GOOD [never reached, if the condition changed so it was then the result would no longer apply] if (c.cond()) diff --git a/java/ql/test/query-tests/MissingCallToSuperClone/Test.java b/java/ql/test/query-tests/MissingCallToSuperClone/Test.java index 77efe645ef5..a236543a695 100644 --- a/java/ql/test/query-tests/MissingCallToSuperClone/Test.java +++ b/java/ql/test/query-tests/MissingCallToSuperClone/Test.java @@ -1,10 +1,10 @@ class IAmAGoodCloneable implements Cloneable { - public Object clone() { + public Object clone() throws CloneNotSupportedException { return super.clone(); } } -class Sub1 extends IAmAGoodCloneable { public Object clone() { return super.clone(); } } +class Sub1 extends IAmAGoodCloneable { public Object clone() throws CloneNotSupportedException { return super.clone(); } } class IAmABadCloneable implements Cloneable { public Object clone() { diff --git a/java/ql/test/query-tests/MissingInstanceofInEquals/GoodReturn.java b/java/ql/test/query-tests/MissingInstanceofInEquals/GoodReturn.java index 593469fe6fb..0de780e4162 100644 --- a/java/ql/test/query-tests/MissingInstanceofInEquals/GoodReturn.java +++ b/java/ql/test/query-tests/MissingInstanceofInEquals/GoodReturn.java @@ -3,7 +3,7 @@ class GoodReturn { @Override public int hashCode() { - getClass().hashCode(); + return getClass().hashCode(); } @Override diff --git a/java/ql/test/query-tests/Nullness/C.java b/java/ql/test/query-tests/Nullness/C.java index c9fe368a394..ac6a5f291da 100644 --- a/java/ql/test/query-tests/Nullness/C.java +++ b/java/ql/test/query-tests/Nullness/C.java @@ -171,7 +171,7 @@ public class C { private void verifyBool(boolean b) { if (!b) { - throw new Exception(); + throw new Error(); } } @@ -192,7 +192,7 @@ public class C { private void verifyNotNull(Object obj) { if (obj == null) { - throw new Exception(); + throw new Error(); } } diff --git a/java/ql/test/query-tests/RangeAnalysis/A.java b/java/ql/test/query-tests/RangeAnalysis/A.java index f2cb4918387..53fbc62f83b 100644 --- a/java/ql/test/query-tests/RangeAnalysis/A.java +++ b/java/ql/test/query-tests/RangeAnalysis/A.java @@ -5,7 +5,7 @@ public class A { public A(int[] arr2, int n) { if (arr2.length % 2 != 0) - throw new Exception(); + throw new Error(); this.arr2 = arr2; this.arr3 = new int[n << 1]; } @@ -168,7 +168,7 @@ public class A { if (n > 0) { a = n > 0 ? new int[3 * n] : null; } - int sum; + int sum = 0; if (a != null) { for (int i = 0; i < a.length; i += 3) { sum += a[i + 2]; // OK diff --git a/java/ql/test/query-tests/UseBraces/UseBraces.java b/java/ql/test/query-tests/UseBraces/UseBraces.java index c823456cd2a..756050b2c44 100644 --- a/java/ql/test/query-tests/UseBraces/UseBraces.java +++ b/java/ql/test/query-tests/UseBraces/UseBraces.java @@ -7,9 +7,9 @@ class UseBraces void f() { } void g() { } void h() { } - void test() + void test(boolean bb) { - int x, y; + int x = 0, y; int[] branches = new int[10]; // If-then statement @@ -67,27 +67,27 @@ class UseBraces // While statement - while(false) + while(bb) { f(); } g(); // No alert - while(false) + while(bb) f(); g(); - while(false) + while(bb ) f(); g(); // Alert g(); // No alert - while(false) + while(bb ) f(); g(); // Alert - while(false) + while(bb) if (x != 0) x = 1; // Do-while statement diff --git a/java/ql/test/query-tests/UselessComparisonTest/Test.java b/java/ql/test/query-tests/UselessComparisonTest/Test.java index 4b9d7488317..eafac84dea5 100644 --- a/java/ql/test/query-tests/UselessComparisonTest/Test.java +++ b/java/ql/test/query-tests/UselessComparisonTest/Test.java @@ -3,7 +3,7 @@ class Test { void test(int x) { z = getInt(); if (x < 0 || z < 0) { - throw new Exception(); + throw new Error(); } int y = 0; if (x >= 0) y++; // useless test due to test in line 5 being false diff --git a/java/ql/test/query-tests/UselessNullCheck/A.java b/java/ql/test/query-tests/UselessNullCheck/A.java index 017629ec516..009f5efadd3 100644 --- a/java/ql/test/query-tests/UselessNullCheck/A.java +++ b/java/ql/test/query-tests/UselessNullCheck/A.java @@ -7,7 +7,7 @@ public class A { new Object(); } catch(Exception e) { if (e == null) { // Useless check - throw new Exception(); + throw new Error(); } } } @@ -16,7 +16,7 @@ public class A { if (o instanceof A) { A a = (A)o; if (a != null) { // Useless check - throw new Exception(); + throw new Error(); } } } diff --git a/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java b/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java index 418975b0281..72ca3ae46f6 100644 --- a/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java +++ b/java/ql/test/query-tests/dead-code/DeadField/ReflectionTest.java @@ -16,7 +16,7 @@ public class ReflectionTest { public int shadowedField; } - public static void main(String[] args) { + public static void main(String[] args) throws NoSuchFieldException { // Ensure the two classes are live, otherwise we might hide some results new ParentClass(); new ChildClass(); diff --git a/java/ql/test/query-tests/dead-code/DeadMethod/ReflectionMethodTest.java b/java/ql/test/query-tests/dead-code/DeadMethod/ReflectionMethodTest.java index 4336655a664..c77718f9750 100644 --- a/java/ql/test/query-tests/dead-code/DeadMethod/ReflectionMethodTest.java +++ b/java/ql/test/query-tests/dead-code/DeadMethod/ReflectionMethodTest.java @@ -19,7 +19,7 @@ public class ReflectionMethodTest { public void test4() { } } - public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException { + public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException { // Get class by name Class.forName("ReflectionTest$TestObject1").getMethod("test1"); // Use classloader diff --git a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java index 46ed97e2d98..b5bee61b965 100644 --- a/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java +++ b/java/ql/test/query-tests/security/CWE-022/semmle/tests/ZipTest.java @@ -3,7 +3,7 @@ import java.nio.file.*; import java.util.zip.*; public class ZipTest { - public void m1(ZipEntry entry, File dir) { + public void m1(ZipEntry entry, File dir) throws Exception { String name = entry.getName(); File file = new File(dir, name); FileOutputStream os = new FileOutputStream(file); // ZipSlip @@ -11,7 +11,7 @@ public class ZipTest { FileWriter fw = new FileWriter(file); // ZipSlip } - public void m2(ZipEntry entry, File dir) { + public void m2(ZipEntry entry, File dir) throws Exception { String name = entry.getName(); File file = new File(dir, name); File canFile = file.getCanonicalFile(); @@ -21,7 +21,7 @@ public class ZipTest { FileOutputStream os = new FileOutputStream(file); // OK } - public void m3(ZipEntry entry, File dir) { + public void m3(ZipEntry entry, File dir) throws Exception { String name = entry.getName(); File file = new File(dir, name); if (!file.toPath().normalize().startsWith(dir.toPath())) @@ -29,20 +29,20 @@ public class ZipTest { FileOutputStream os = new FileOutputStream(file); // OK } - private void validate(File tgtdir, File file) { + private void validate(File tgtdir, File file) throws Exception { File canFile = file.getCanonicalFile(); if (!canFile.toPath().startsWith(tgtdir.toPath())) throw new Exception(); } - public void m4(ZipEntry entry, File dir) { + public void m4(ZipEntry entry, File dir) throws Exception { String name = entry.getName(); File file = new File(dir, name); validate(dir, file); FileOutputStream os = new FileOutputStream(file); // OK } - public void m5(ZipEntry entry, File dir) { + public void m5(ZipEntry entry, File dir) throws Exception { String name = entry.getName(); File file = new File(dir, name); Path absfile = file.toPath().toAbsolutePath().normalize(); @@ -52,7 +52,7 @@ public class ZipTest { FileOutputStream os = new FileOutputStream(file); // OK } - public void m6(ZipEntry entry, Path dir) { + public void m6(ZipEntry entry, Path dir) throws Exception { String canonicalDest = dir.toFile().getCanonicalPath(); Path target = dir.resolve(entry.getName()); String canonicalTarget = target.toFile().getCanonicalPath(); diff --git a/java/ql/test/query-tests/security/CWE-078/Test.java b/java/ql/test/query-tests/security/CWE-078/Test.java index 6e185b86bbd..1ac5dc47882 100644 --- a/java/ql/test/query-tests/security/CWE-078/Test.java +++ b/java/ql/test/query-tests/security/CWE-078/Test.java @@ -3,7 +3,7 @@ import java.util.List; import java.util.ArrayList; class Test { - public static void shellCommand(String arg) { + public static void shellCommand(String arg) throws java.io.IOException { ProcessBuilder pb = new ProcessBuilder("/bin/bash -c echo " + arg); pb.start(); @@ -25,7 +25,7 @@ class Test { pb.start(); } - public static void nonShellCommand(String arg) { + public static void nonShellCommand(String arg) throws java.io.IOException { ProcessBuilder pb = new ProcessBuilder("./customTool " + arg); pb.start(); @@ -46,7 +46,7 @@ class Test { pb.start(); } - public static void relativeCommand() { + public static void relativeCommand() throws java.io.IOException { ProcessBuilder pb = new ProcessBuilder("ls"); pb.start(); @@ -54,11 +54,11 @@ class Test { pb.start(); } - public static void main(String[] args) { + public static void main(String[] args) throws java.io.IOException { String arg = args.length > 1 ? args[1] : "default"; shellCommand(arg); nonShellCommand(arg); relativeCommand(); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java b/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java index 005271998ba..c893e0b8eef 100644 --- a/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java +++ b/java/ql/test/query-tests/security/CWE-297/UnsafeHostnameVerification.java @@ -66,7 +66,7 @@ public class UnsafeHostnameVerification { HostnameVerifier verifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { - verify(hostname, session.getPeerCertificates()); + try { verify(hostname, session.getPeerCertificates()); } catch (Exception e) { throw new RuntimeException(); } return true; // GOOD [but detected as BAD]. The verification of the certificate is done in // another method and // in the case of a mismatch, an `Exception` is thrown so the `return true` diff --git a/java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java b/java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java index 568a9d89f85..9e2f3f923e8 100644 --- a/java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java +++ b/java/ql/test/query-tests/security/CWE-311/CWE-319/Test.java @@ -3,7 +3,7 @@ import javax.net.ssl.HttpsURLConnection; import java.io.*; class Test { - public void m1(HttpURLConnection connection) { + public void m1(HttpURLConnection connection) throws java.io.IOException { InputStream input; if (connection instanceof HttpsURLConnection) { input = connection.getInputStream(); // OK diff --git a/java/ql/test/query-tests/security/CWE-421/semmle/Test.java b/java/ql/test/query-tests/security/CWE-421/semmle/Test.java index 31d20ae133a..0e2dc665a4b 100644 --- a/java/ql/test/query-tests/security/CWE-421/semmle/Test.java +++ b/java/ql/test/query-tests/security/CWE-421/semmle/Test.java @@ -31,7 +31,7 @@ class Test { return true; } - public void doConnect(int desiredPort, String username) { + public void doConnect(int desiredPort, String username) throws Exception { ServerSocket listenSocket = new ServerSocket(desiredPort); if (isAuthenticated(username)) { @@ -56,7 +56,7 @@ class Test { } - public void doConnectChannel(int desiredPort, String username) { + public void doConnectChannel(int desiredPort, String username) throws Exception { ServerSocketChannel listenChannel = ServerSocketChannel.open(); SocketAddress port = new InetSocketAddress(desiredPort); listenChannel.bind(port); 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 3b3de5f8ed2..d1ef4859823 100644 --- a/java/ql/test/query-tests/security/CWE-502/A.java +++ b/java/ql/test/query-tests/security/CWE-502/A.java @@ -9,32 +9,32 @@ import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.Yaml; public class A { - public Object deserialize1(Socket sock) { + public Object deserialize1(Socket sock) throws java.io.IOException, ClassNotFoundException { InputStream inputStream = sock.getInputStream(); ObjectInputStream in = new ObjectInputStream(inputStream); return in.readObject(); // unsafe } - public Object deserialize2(Socket sock) { + public Object deserialize2(Socket sock) throws java.io.IOException, ClassNotFoundException { InputStream inputStream = sock.getInputStream(); ObjectInputStream in = new ObjectInputStream(inputStream); return in.readUnshared(); // unsafe } - public Object deserialize3(Socket sock) { + public Object deserialize3(Socket sock) throws java.io.IOException { InputStream inputStream = sock.getInputStream(); XMLDecoder d = new XMLDecoder(inputStream); return d.readObject(); // unsafe } - public Object deserialize4(Socket sock) { + public Object deserialize4(Socket sock) throws java.io.IOException { XStream xs = new XStream(); InputStream inputStream = sock.getInputStream(); Reader reader = new InputStreamReader(inputStream); return xs.fromXML(reader); // unsafe } - public void deserialize5(Socket sock) { + public void deserialize5(Socket sock) throws java.io.IOException { Kryo kryo = new Kryo(); Input input = new Input(sock.getInputStream()); A a1 = kryo.readObject(input, A.class); // unsafe @@ -42,20 +42,20 @@ public class A { Object o = kryo.readClassAndObject(input); // unsafe } - private Kryo getSafeKryo() { + private Kryo getSafeKryo() throws java.io.IOException { Kryo kryo = new Kryo(); kryo.setRegistrationRequired(true); // ... kryo.register(A.class) ... return kryo; } - public void deserialize6(Socket sock) { + public void deserialize6(Socket sock) throws java.io.IOException { Kryo kryo = getSafeKryo(); Input input = new Input(sock.getInputStream()); Object o = kryo.readClassAndObject(input); // OK } - public void deserializeSnakeYaml(Socket sock) { + public void deserializeSnakeYaml(Socket sock) throws java.io.IOException { Yaml yaml = new Yaml(); InputStream input = sock.getInputStream(); Object o = yaml.load(input); //unsafe @@ -65,7 +65,7 @@ public class A { A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //unsafe } - public void deserializeSnakeYaml2(Socket sock) { + public void deserializeSnakeYaml2(Socket sock) throws java.io.IOException { Yaml yaml = new Yaml(new Constructor()); InputStream input = sock.getInputStream(); Object o = yaml.load(input); //unsafe @@ -75,7 +75,7 @@ public class A { A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //unsafe } - public void deserializeSnakeYaml3(Socket sock) { + public void deserializeSnakeYaml3(Socket sock) throws java.io.IOException { Yaml yaml = new Yaml(new SafeConstructor()); InputStream input = sock.getInputStream(); Object o = yaml.load(input); //OK @@ -85,7 +85,7 @@ public class A { A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //OK } - public void deserializeSnakeYaml4(Socket sock) { + public void deserializeSnakeYaml4(Socket sock) throws java.io.IOException { Yaml yaml = new Yaml(new Constructor(A.class)); InputStream input = sock.getInputStream(); Object o = yaml.load(input); //OK diff --git a/java/ql/test/query-tests/security/CWE-502/B.java b/java/ql/test/query-tests/security/CWE-502/B.java index 671442a9346..a12555edd70 100644 --- a/java/ql/test/query-tests/security/CWE-502/B.java +++ b/java/ql/test/query-tests/security/CWE-502/B.java @@ -3,19 +3,19 @@ import java.net.Socket; import com.alibaba.fastjson.JSON; public class B { - public Object deserializeJson1(Socket sock) { + public Object deserializeJson1(Socket sock) throws java.io.IOException { InputStream inputStream = sock.getInputStream(); return JSON.parseObject(inputStream, null); // unsafe } - public Object deserializeJson2(Socket sock) { + public Object deserializeJson2(Socket sock) throws java.io.IOException { InputStream inputStream = sock.getInputStream(); byte[] bytes = new byte[100]; inputStream.read(bytes); return JSON.parse(bytes); // unsafe } - public Object deserializeJson3(Socket sock) { + public Object deserializeJson3(Socket sock) throws java.io.IOException { InputStream inputStream = sock.getInputStream(); byte[] bytes = new byte[100]; inputStream.read(bytes); @@ -23,7 +23,7 @@ public class B { return JSON.parseObject(s); // unsafe } - public Object deserializeJson4(Socket sock) { + public Object deserializeJson4(Socket sock) throws java.io.IOException { InputStream inputStream = sock.getInputStream(); byte[] bytes = new byte[100]; inputStream.read(bytes); diff --git a/java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java b/java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java index f70b44e2f1a..cb25141a90d 100644 --- a/java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java +++ b/java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java @@ -102,7 +102,7 @@ class DocumentBuilderTests { builder.parse(source.getInputStream()); //unsafe } - private static DocumentBuilderFactory getDocumentBuilderFactory() { + private static DocumentBuilderFactory getDocumentBuilderFactory() throws Exception { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); String feature = ""; feature = "http://xml.org/sax/features/external-parameter-entities"; @@ -115,8 +115,8 @@ class DocumentBuilderTests { private static final ThreadLocal XML_DOCUMENT_BUILDER = new ThreadLocal() { @Override protected DocumentBuilder initialValue() { - DocumentBuilderFactory factory = getDocumentBuilderFactory(); try { + DocumentBuilderFactory factory = getDocumentBuilderFactory(); return factory.newDocumentBuilder(); } catch (Exception ex) { throw new RuntimeException(ex); diff --git a/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java index ec1dfd1289c..8717203802d 100644 --- a/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-732/semmle/tests/Test.java @@ -31,11 +31,11 @@ class Test { new FileInputStream(f2); } - public static void readFile(File f) { + public static void readFile(File f) throws java.io.FileNotFoundException { new FileReader(f); } public static void setWorldWritable(File f) { f.setWritable(true, false); } -} \ No newline at end of file +} diff --git a/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java b/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java index 9092bfee427..e02364c05ec 100644 --- a/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java +++ b/java/ql/test/query-tests/security/CWE-833/semmle/tests/MethodAccessLockOrder.java @@ -26,9 +26,9 @@ class MethodAccessLockOrder { public boolean initiateTransfer(boolean fromSavings, int amount) { // AVOID: inconsistent lock order if (fromSavings) { - primary.transferFrom(savings, amount); + return primary.transferFrom(savings, amount); } else { - savings.transferFrom(primary, amount); + return savings.transferFrom(primary, amount); } } diff --git a/java/ql/test/stubs/google-android-9.0.0/android/app/Activity.java b/java/ql/test/stubs/google-android-9.0.0/android/app/Activity.java index 19a2662b96c..e04f68a203d 100644 --- a/java/ql/test/stubs/google-android-9.0.0/android/app/Activity.java +++ b/java/ql/test/stubs/google-android-9.0.0/android/app/Activity.java @@ -1019,6 +1019,7 @@ public class Activity { * @see Activity#requireViewById(int) */ public T findViewById(int id) { + return null; } /** @@ -1141,4 +1142,4 @@ public class Activity { */ public void startActivities(Intent[] intents, Bundle options) { } -} \ No newline at end of file +} diff --git a/java/ql/test/stubs/google-android-9.0.0/android/content/Intent.java b/java/ql/test/stubs/google-android-9.0.0/android/content/Intent.java index 292069c0f71..09422c7a48a 100644 --- a/java/ql/test/stubs/google-android-9.0.0/android/content/Intent.java +++ b/java/ql/test/stubs/google-android-9.0.0/android/content/Intent.java @@ -821,6 +821,7 @@ public class Intent implements Parcelable, Cloneable { */ @Deprecated public static Intent getIntent(String uri) { + return null; } /** @@ -845,6 +846,7 @@ public class Intent implements Parcelable, Cloneable { * @see #toUri */ public static Intent parseUri(String uri, int flags) { + return null; } /** @@ -2069,4 +2071,4 @@ public class Intent implements Parcelable, Cloneable { return null; } -} \ No newline at end of file +} diff --git a/java/ql/test/stubs/google-android-9.0.0/android/os/BaseBundle.java b/java/ql/test/stubs/google-android-9.0.0/android/os/BaseBundle.java index 4b85ae8e67a..3ac33642ab4 100644 --- a/java/ql/test/stubs/google-android-9.0.0/android/os/BaseBundle.java +++ b/java/ql/test/stubs/google-android-9.0.0/android/os/BaseBundle.java @@ -97,6 +97,7 @@ public class BaseBundle { * @hide */ public String getPairValue() { + return null; } /** diff --git a/java/ql/test/stubs/google-android-9.0.0/android/os/Parcel.java b/java/ql/test/stubs/google-android-9.0.0/android/os/Parcel.java index 2670e258e4f..077da662edb 100644 --- a/java/ql/test/stubs/google-android-9.0.0/android/os/Parcel.java +++ b/java/ql/test/stubs/google-android-9.0.0/android/os/Parcel.java @@ -229,6 +229,7 @@ public final class Parcel { } public final float[] createFloatArray() { + return null; } public final void readFloatArray(float[] val) { diff --git a/java/ql/test/stubs/google-android-9.0.0/androidx/security/crypto/EncryptedSharedPreferences.java b/java/ql/test/stubs/google-android-9.0.0/androidx/security/crypto/EncryptedSharedPreferences.java index db918d448f2..8ca1443d049 100644 --- a/java/ql/test/stubs/google-android-9.0.0/androidx/security/crypto/EncryptedSharedPreferences.java +++ b/java/ql/test/stubs/google-android-9.0.0/androidx/security/crypto/EncryptedSharedPreferences.java @@ -85,6 +85,7 @@ public final class EncryptedSharedPreferences implements SharedPreferences { PrefKeyEncryptionScheme prefKeyEncryptionScheme, PrefValueEncryptionScheme prefValueEncryptionScheme) throws GeneralSecurityException, IOException { + return null; } /** @@ -168,4 +169,4 @@ public final class EncryptedSharedPreferences implements SharedPreferences { public void unregisterOnSharedPreferenceChangeListener( OnSharedPreferenceChangeListener listener) { } -} \ No newline at end of file +} From e5331a4735546448375dc9ce062d903e48956f02 Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Tue, 9 Feb 2021 09:17:35 -0500 Subject: [PATCH 256/429] Java: accept changes in expected output --- .../dataflow/taintsources/remote.expected | 10 +++++----- .../semmle/tests/LockOrderInconsistency.expected | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/java/ql/test/library-tests/dataflow/taintsources/remote.expected b/java/ql/test/library-tests/dataflow/taintsources/remote.expected index 57acdb6d26c..e4f1dac7ca6 100644 --- a/java/ql/test/library-tests/dataflow/taintsources/remote.expected +++ b/java/ql/test/library-tests/dataflow/taintsources/remote.expected @@ -5,21 +5,21 @@ | A.java:41:5:41:53 | getInputStream(...) | A.java:41:5:41:53 | getInputStream(...) | | A.java:42:5:42:45 | getInputStream(...) | A.java:42:5:42:45 | getInputStream(...) | | A.java:43:5:43:47 | getHostName(...) | A.java:43:5:43:47 | getHostName(...) | -| IntentSources.java:9:20:9:35 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1057:19:1057:32 | parameter this | +| IntentSources.java:9:20:9:35 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1059:19:1059:32 | parameter this | | IntentSources.java:9:20:9:35 | getIntent(...) | IntentSources.java:9:20:9:35 | getIntent(...) | | IntentSources.java:9:20:9:35 | getIntent(...) | IntentSources.java:9:20:9:57 | getStringExtra(...) | | IntentSources.java:9:20:9:35 | getIntent(...) | IntentSources.java:10:29:10:35 | trouble | -| IntentSources.java:16:20:16:30 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1057:19:1057:32 | parameter this | +| IntentSources.java:16:20:16:30 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1059:19:1059:32 | parameter this | | IntentSources.java:16:20:16:30 | getIntent(...) | IntentSources.java:16:20:16:30 | getIntent(...) | | IntentSources.java:16:20:16:30 | getIntent(...) | IntentSources.java:16:20:16:52 | getStringExtra(...) | | IntentSources.java:16:20:16:30 | getIntent(...) | IntentSources.java:17:29:17:35 | trouble | -| IntentSources.java:23:20:23:30 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1356:19:1356:27 | parameter this | -| IntentSources.java:23:20:23:30 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/os/BaseBundle.java:599:19:599:27 | parameter this | +| IntentSources.java:23:20:23:30 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1358:19:1358:27 | parameter this | +| IntentSources.java:23:20:23:30 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/os/BaseBundle.java:600:19:600:27 | parameter this | | IntentSources.java:23:20:23:30 | getIntent(...) | IntentSources.java:23:20:23:30 | getIntent(...) | | IntentSources.java:23:20:23:30 | getIntent(...) | IntentSources.java:23:20:23:42 | getExtras(...) | | IntentSources.java:23:20:23:30 | getIntent(...) | IntentSources.java:23:20:23:59 | getString(...) | | IntentSources.java:23:20:23:30 | getIntent(...) | IntentSources.java:24:29:24:35 | trouble | -| IntentSources.java:33:20:33:33 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1057:19:1057:32 | parameter this | +| IntentSources.java:33:20:33:33 | getIntent(...) | ../../../stubs/google-android-9.0.0/android/content/Intent.java:1059:19:1059:32 | parameter this | | IntentSources.java:33:20:33:33 | getIntent(...) | IntentSources.java:33:20:33:33 | getIntent(...) | | IntentSources.java:33:20:33:33 | getIntent(...) | IntentSources.java:33:20:33:55 | getStringExtra(...) | | IntentSources.java:33:20:33:33 | getIntent(...) | IntentSources.java:34:29:34:35 | trouble | diff --git a/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.expected b/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.expected index 89a404374cc..995d2a75277 100644 --- a/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.expected +++ b/java/ql/test/query-tests/security/CWE-833/semmle/tests/LockOrderInconsistency.expected @@ -1,4 +1,4 @@ -| MethodAccessLockOrder.java:29:4:29:40 | transferFrom(...) | Synchronization here and $@ may be performed in reverse order starting $@ and result in deadlock. | MethodAccessLockOrder.java:8:21:8:41 | subtract(...) | here | MethodAccessLockOrder.java:31:4:31:40 | transferFrom(...) | here | +| MethodAccessLockOrder.java:29:11:29:47 | transferFrom(...) | Synchronization here and $@ may be performed in reverse order starting $@ and result in deadlock. | MethodAccessLockOrder.java:8:21:8:41 | subtract(...) | here | MethodAccessLockOrder.java:31:11:31:47 | transferFrom(...) | here | | ReentrantLockOrder.java:11:4:11:21 | lock(...) | Synchronization here and $@ may be performed in reverse order starting $@ and result in deadlock. | ReentrantLockOrder.java:12:4:12:21 | lock(...) | here | ReentrantLockOrder.java:28:4:28:21 | lock(...) | here | | ReentrantLockOrder.java:28:4:28:21 | lock(...) | Synchronization here and $@ may be performed in reverse order starting $@ and result in deadlock. | ReentrantLockOrder.java:29:4:29:21 | lock(...) | here | ReentrantLockOrder.java:11:4:11:21 | lock(...) | here | | SynchronizedStmtLockOrder.java:8:16:8:26 | primaryLock | Synchronization here and $@ may be performed in reverse order starting $@ and result in deadlock. | SynchronizedStmtLockOrder.java:9:17:9:27 | savingsLock | here | SynchronizedStmtLockOrder.java:22:16:22:26 | savingsLock | here | From cc031118dd8cc4b1d03652e325a4d648046f6239 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:19:30 +0000 Subject: [PATCH 257/429] Update CONTRIBUTING.md Co-authored-by: hubwriter --- CONTRIBUTING.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf7faeaa213..f9f6fe310a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,8 +51,7 @@ If you have an idea for a query that you would like to share with other CodeQL u 6. **Query help files and unit tests** - - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. - - see [Supported CodeQL queries and libraries](docs/supported-queries.md) for more information about contributing query help files and unit tests. + - Query help (`.qhelp`) files and unit tests are optional (but strongly encouraged!) for queries in the `experimental` directories. For more information about contributing query help files and unit tests, see [Supported CodeQL queries and libraries](docs/supported-queries.md). Experimental queries and libraries may not be actively maintained as the supported libraries evolve. They may also be changed in backwards-incompatible ways or may be removed entirely in the future without deprecation warnings. From d475e55ec0cba77b38fb07baa7b4ebe6f778ec89 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 9 Feb 2021 15:20:03 +0000 Subject: [PATCH 258/429] Update cpp/ql/test/README.md Co-authored-by: hubwriter --- cpp/ql/test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/test/README.md b/cpp/ql/test/README.md index efa020a074f..9de2b10e1b8 100644 --- a/cpp/ql/test/README.md +++ b/cpp/ql/test/README.md @@ -1,6 +1,6 @@ # C/C++ CodeQL tests -This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. The principles under 'Copying code' also apply to any other C/C++ code in this repository, such as examples linked from query `.qhelp` files in `cpp/ql/src`. See [Contributing to CodeQL](/CONTRIBUTING.md) for more general information about contributing to this repository. +This document provides additional information about the C/C++ CodeQL tests located in `cpp/ql/test`. The principles under "Copying code", below, also apply to any other C/C++ code in this repository, such as examples linked from query `.qhelp` files in `cpp/ql/src`. For more general information about contributing to this repository, see [Contributing to CodeQL](/CONTRIBUTING.md). The tests can be run through Visual Studio Code. Advanced users may also use the `codeql test run` command. From e5970f4c652a6088249c82c02b1450ab0c5a81bb Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 9 Feb 2021 20:09:24 +0100 Subject: [PATCH 259/429] Data flow: Take `clearsContent()` into account in flow exploration --- .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() From 1f9b42f9ab19c24f9150430f6341a5b7d792b819 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 9 Feb 2021 20:10:23 +0100 Subject: [PATCH 260/429] Data flow: Sync files --- cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 2 ++ cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 2 ++ cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 2 ++ cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 2 ++ .../src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll | 2 ++ .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 2 ++ .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 2 ++ .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 2 ++ .../src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 2 ++ .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 2 ++ .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 2 ++ .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 2 ++ .../src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 2 ++ java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 2 ++ .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 2 ++ .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 2 ++ .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 2 ++ .../ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 2 ++ .../ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll | 2 ++ .../src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll | 2 ++ .../src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll | 2 ++ .../src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll | 2 ++ 22 files changed, 44 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index d9f5acdd279..59cc8d529a7 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index d9f5acdd279..59cc8d529a7 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll index d9f5acdd279..59cc8d529a7 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index d9f5acdd279..59cc8d529a7 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index d9f5acdd279..59cc8d529a7 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index d9f5acdd279..59cc8d529a7 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -3598,6 +3598,7 @@ private module FlowExploration { or exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, sc1, sc2, ap, config) and + not clearsContent(node, ap.getHead()) and not fullBarrier(node, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() ) @@ -3611,6 +3612,7 @@ private module FlowExploration { exists(PartialPathNodeFwd mid | partialPathStep(mid, node, cc, sc1, sc2, ap, config) and not fullBarrier(node, config) and + not clearsContent(node, ap.getHead().getContent()) and if node instanceof CastingNode then compatibleTypes(getNodeType(node), ap.getType()) else any() From 3b4357792bdb194e31918fbd007e366a43aac34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Wed, 10 Feb 2021 12:21:48 +0100 Subject: [PATCH 261/429] Remove sanitizing condition which does not prevent vulnerability. --- .../ql/src/semmle/code/java/frameworks/SnakeYaml.qll | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll b/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll index 5c277b7200b..04b3be0a3dc 100644 --- a/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll +++ b/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll @@ -7,13 +7,6 @@ import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.DataFlow2 import semmle.code.java.dataflow.DataFlow3 -/** - * The class `org.yaml.snakeyaml.constructor.Constructor`. - */ -class SnakeYamlConstructor extends RefType { - SnakeYamlConstructor() { this.hasQualifiedName("org.yaml.snakeyaml.constructor", "Constructor") } -} - /** * The class `org.yaml.snakeyaml.constructor.SafeConstructor`. */ @@ -24,14 +17,11 @@ class SnakeYamlSafeConstructor extends RefType { } /** - * An instance of `SafeConstructor` or a `Constructor` that only allows the type that is passed into its argument. + * An instance of `SafeConstructor` */ class SafeSnakeYamlConstruction extends ClassInstanceExpr { SafeSnakeYamlConstruction() { this.getConstructedType() instanceof SnakeYamlSafeConstructor - or - this.getConstructedType() instanceof SnakeYamlConstructor and - this.getNumArgument() > 0 } } From 0cf3a29429dacc1e0876d1198b71ec1b5aaa7e7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Wed, 10 Feb 2021 13:09:57 +0100 Subject: [PATCH 262/429] Add support for Apache Commons Lang ArrayUtils --- .../code/java/frameworks/apache/Lang.qll | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index dcf91b36132..e31b2e30861 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -1,27 +1,58 @@ /** Definitions related to the Apache Commons Lang library. */ import java +private import semmle.code.java.dataflow.FlowSteps -/*--- Types ---*/ -/** The class `org.apache.commons.lang.RandomStringUtils` or `org.apache.commons.lang3.RandomStringUtils`. */ +/** + * The class `org.apache.commons.lang.RandomStringUtils` or `org.apache.commons.lang3.RandomStringUtils`. + */ class TypeApacheRandomStringUtils extends Class { TypeApacheRandomStringUtils() { - hasQualifiedName("org.apache.commons.lang", "RandomStringUtils") or - hasQualifiedName("org.apache.commons.lang3", "RandomStringUtils") + this.hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "RandomStringUtils") + } +} + +/** + * The class `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils`. + */ +class TypeApacheArrayUtils extends Class { + TypeApacheArrayUtils() { + hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "ArrayUtils") } } -/*--- Methods ---*/ /** * The method `deserialize` in either `org.apache.commons.lang.SerializationUtils` * or `org.apache.commons.lang3.SerializationUtils`. */ class MethodApacheSerializationUtilsDeserialize extends Method { MethodApacheSerializationUtilsDeserialize() { - ( - this.getDeclaringType().hasQualifiedName("org.apache.commons.lang", "SerializationUtils") or - this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "SerializationUtils") - ) and + this.getDeclaringType().hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "SerializationUtils") and this.hasName("deserialize") } } + +/** + * A taint preserving method on `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils` + */ +private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingCallable { + ApacheLangArrayUtilsTaintPreservingMethod() { + this.getDeclaringType() instanceof TypeApacheArrayUtils + } + + override predicate returnsTaintFrom(int src) { + this.hasName(["addAll", "addFirst"]) and + src = [0 .. getNumberOfParameters()] + or + this.hasName(["clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse", "shift", "shuffle", "subarray", "swap", "toArray", "toMap", "toObject", "toPrimitive", "toString", "toStringArray"]) and + src = 0 + or + this.hasName("add") and + this.getNumberOfParameters() = 2 and + src = [0,1,2] + or + this.hasName("add") and + this.getNumberOfParameters() = 3 and + src = [0, 2] + } +} From 645b021845e4a2f8b36379d1bdec9c1f707e4234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Wed, 10 Feb 2021 13:20:29 +0100 Subject: [PATCH 263/429] Add support for the Preconditions Class in the Guava framework --- .../code/java/frameworks/guava/Guava.qll | 1 + .../java/frameworks/guava/Preconditions.qll | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 java/ql/src/semmle/code/java/frameworks/guava/Preconditions.qll diff --git a/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll b/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll index 547a920d749..c6bdf0ea9b9 100644 --- a/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll +++ b/java/ql/src/semmle/code/java/frameworks/guava/Guava.qll @@ -5,3 +5,4 @@ import java import StringUtils import Collections +import Preconditions diff --git a/java/ql/src/semmle/code/java/frameworks/guava/Preconditions.qll b/java/ql/src/semmle/code/java/frameworks/guava/Preconditions.qll new file mode 100644 index 00000000000..f9fce517988 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/guava/Preconditions.qll @@ -0,0 +1,23 @@ +/** Definitions of flow steps through the Preconditions class in the Guava framework. */ + +import java +private import semmle.code.java.dataflow.FlowSteps + +/** + * The class `com.google.common.base.Preconditions`. + */ +class TypeGuavaPreconditions extends Class { + TypeGuavaPreconditions() { this.hasQualifiedName("com.google.common.base", "Preconditions") } +} + +/** + * A method that returns its argumnets. + */ +private class GuavaPreconditionsMethod extends TaintPreservingCallable { + GuavaPreconditionsMethod() { + this.getDeclaringType() instanceof TypeGuavaPreconditions and + this.hasName("checkNotNull") + } + + override predicate returnsTaintFrom(int src) { src = 0 } +} From 5c82ff83ded47c67bbf5e4ae0e33da569ac73eff Mon Sep 17 00:00:00 2001 From: intrigus Date: Wed, 10 Feb 2021 13:57:51 +0100 Subject: [PATCH 264/429] Java: Fix qhelp, fix CWE reference --- .../Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp | 3 +-- .../Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp index 38b37901c0c..7327573b8ba 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.qhelp @@ -10,13 +10,12 @@ Versions smaller than 6.24 by default ignore any HTTPS certificate errors thereb -

    Do either of these: +

    Do either of these:

    • Update to version 6.24 or 7.x.x as these correctly reject certificate errors by default.
    • Add a custom implementation of the LoadHandler interface whose onCertificateError method always returns true indicating that loading should be cancelled. Then use the setLoadHandler method with your custom LoadHandler on every Browser you use.
    -

    diff --git a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql index 4046f4e9606..aecffaf3f3b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-295/JxBrowserWithoutCertValidation.ql @@ -4,7 +4,7 @@ * @kind problem * @id java/jxbrowser/disabled-certificate-validation * @tags security - * external/cwe-295 + * external/cwe/cwe-295 */ import java From 44ca2e26a64cea5e5495e8fbbf64562a2839492e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 17:08:18 +0100 Subject: [PATCH 265/429] add taint-step to XML parsers --- .../javascript/frameworks/XmlParsers.qll | 25 ++++++++++++++++--- .../TaintTracking/BasicTaintTracking.expected | 1 + .../test/library-tests/TaintTracking/xml.js | 10 ++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 javascript/ql/test/library-tests/TaintTracking/xml.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll index 060fa62ee76..3a78bda7b1a 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll @@ -25,6 +25,9 @@ module XML { /** Holds if this call to the XML parser resolves entities of the given `kind`. */ abstract predicate resolvesEntities(EntityKind kind); + + /** Gets a reference to a value resulting from parsing the XML. */ + js::DataFlow::Node getAResult() { none() } } /** @@ -98,10 +101,11 @@ module XML { * An invocation of `expat.Parser.parse` or `expat.Parser.write`. */ class ExpatParserInvocation extends ParserInvocation { + js::DataFlow::NewNode parser; + ExpatParserInvocation() { - exists(string m | m = "parse" or m = "write" | - this = moduleMethodCall("node-expat", "Parser", m) - ) + parser = js::DataFlow::moduleMember("node-expat", "Parser").getAnInstantiation() and + this = parser.getAMemberCall(["parse", "write"]).asExpr() } override js::Expr getSourceArgument() { result = getArgument(0) } @@ -110,6 +114,10 @@ module XML { // only internal entities are resolved by default kind = InternalEntity() } + + override js::DataFlow::Node getAResult() { + result = parser.getAMemberCall("on").getABoundCallbackParameter(1, _) + } } /** @@ -160,4 +168,15 @@ module XML { override predicate resolvesEntities(XML::EntityKind kind) { kind = InternalEntity() } } + + private class XMLParserTaintStep extends js::TaintTracking::AdditionalTaintStep { + XML::ParserInvocation parser; + + XMLParserTaintStep() { this.asExpr() = parser } + + override predicate step(js::DataFlow::Node pred, js::DataFlow::Node succ) { + pred.asExpr() = parser.getSourceArgument() and + succ = parser.getAResult() + } + } } diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 24fcbb5a6ef..3af34b132d0 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -145,3 +145,4 @@ typeInferenceMismatch | tst.js:2:13:2:20 | source() | tst.js:45:10:45:24 | x.map(x2 => x2) | | tst.js:2:13:2:20 | source() | tst.js:47:10:47:30 | Buffer. ... 'hex') | | tst.js:2:13:2:20 | source() | tst.js:48:10:48:22 | new Buffer(x) | +| xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | diff --git a/javascript/ql/test/library-tests/TaintTracking/xml.js b/javascript/ql/test/library-tests/TaintTracking/xml.js new file mode 100644 index 00000000000..d7e25268493 --- /dev/null +++ b/javascript/ql/test/library-tests/TaintTracking/xml.js @@ -0,0 +1,10 @@ +(function () { + var Parser = require("node-expat").Parser + var parser = new Parser(); + + parser.write(source()); + + parser.on("text", text => { + sink(text); // NOT OK + }); +})(); \ No newline at end of file From c43025d7b3a741a5ba652013841807ce0f9343a8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 17:32:14 +0100 Subject: [PATCH 266/429] add model for xml2js --- .../javascript/frameworks/XmlParsers.qll | 25 +++++++++++++++++++ .../TaintTracking/BasicTaintTracking.expected | 1 + .../test/library-tests/TaintTracking/xml.js | 5 ++++ 3 files changed, 31 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll index 3a78bda7b1a..c9f2b993a5c 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll @@ -169,6 +169,31 @@ module XML { override predicate resolvesEntities(XML::EntityKind kind) { kind = InternalEntity() } } + /** + * An invocation of `xml2js`. + */ + private class Xml2JSInvocation extends XML::ParserInvocation { + js::DataFlow::CallNode call; + + Xml2JSInvocation() { + exists(js::API::Node imp | imp = js::API::moduleImport("xml2js") | + call = [imp, imp.getMember("Parser").getInstance()].getMember("parseString").getACall() and + this = call.asExpr() + ) + } + + override js::Expr getSourceArgument() { result = getArgument(0) } + + override predicate resolvesEntities(XML::EntityKind kind) { + // sax-js (the parser used) does not expand entities. + none() + } + + override js::DataFlow::Node getAResult() { + result = call.getABoundCallbackParameter(call.getNumArgument() - 1, 1) + } + } + private class XMLParserTaintStep extends js::TaintTracking::AdditionalTaintStep { XML::ParserInvocation parser; diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 3af34b132d0..8b2453a3cb1 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -146,3 +146,4 @@ typeInferenceMismatch | tst.js:2:13:2:20 | source() | tst.js:47:10:47:30 | Buffer. ... 'hex') | | tst.js:2:13:2:20 | source() | tst.js:48:10:48:22 | new Buffer(x) | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | +| xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | diff --git a/javascript/ql/test/library-tests/TaintTracking/xml.js b/javascript/ql/test/library-tests/TaintTracking/xml.js index d7e25268493..25e733c8fab 100644 --- a/javascript/ql/test/library-tests/TaintTracking/xml.js +++ b/javascript/ql/test/library-tests/TaintTracking/xml.js @@ -7,4 +7,9 @@ parser.on("text", text => { sink(text); // NOT OK }); + + var parseString = require('xml2js').parseString; + parseString(source(), function (err, result) { + sink(result); // NOT OK + }); })(); \ No newline at end of file From 73f7cd149f149d635384e419f186f7c6d49234c8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 17:50:49 +0100 Subject: [PATCH 267/429] add model for `sax` --- .../javascript/frameworks/XmlParsers.qll | 32 +++++++++++++++++++ .../TaintTracking/BasicTaintTracking.expected | 1 + .../test/library-tests/TaintTracking/xml.js | 10 ++++++ 3 files changed, 43 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll index c9f2b993a5c..de203a88f04 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll @@ -194,6 +194,38 @@ module XML { } } + /** + * An invocation of `sax`. + */ + private class SaxInvocation extends XML::ParserInvocation { + js::DataFlow::InvokeNode parser; + + SaxInvocation() { + exists(js::API::Node imp | imp = js::API::moduleImport("sax") | + parser = imp.getMember("parser").getACall() + or + parser = imp.getMember("SAXParser").getAnInstantiation() + ) and + this = parser.getAMemberCall("write").asExpr() + } + + override js::Expr getSourceArgument() { result = getArgument(0) } + + override predicate resolvesEntities(XML::EntityKind kind) { + // sax-js does not expand entities. + none() + } + + override js::DataFlow::Node getAResult() { + result = + parser + .getAPropertyWrite(any(string s | s.matches("on%"))) + .getRhs() + .getAFunctionValue() + .getAParameter() + } + } + private class XMLParserTaintStep extends js::TaintTracking::AdditionalTaintStep { XML::ParserInvocation parser; diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 8b2453a3cb1..39a370ecf71 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -147,3 +147,4 @@ typeInferenceMismatch | tst.js:2:13:2:20 | source() | tst.js:48:10:48:22 | new Buffer(x) | | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | +| xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | diff --git a/javascript/ql/test/library-tests/TaintTracking/xml.js b/javascript/ql/test/library-tests/TaintTracking/xml.js index 25e733c8fab..a603f3d1c0e 100644 --- a/javascript/ql/test/library-tests/TaintTracking/xml.js +++ b/javascript/ql/test/library-tests/TaintTracking/xml.js @@ -12,4 +12,14 @@ parseString(source(), function (err, result) { sink(result); // NOT OK }); + + var sax = require("sax"); + var parser = sax.parser(strict); + + parser.onattribute = function (attr) { + sink(attr); // NOT OK + }; + + parser.write(source()).close(); + })(); \ No newline at end of file From e2a66bf3ed5474f6b84528126754b4ba5bb9cc48 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 18:16:19 +0100 Subject: [PATCH 268/429] add model for `xml-js` --- .../javascript/frameworks/XmlParsers.qll | 21 +++++++++++++++++++ .../TaintTracking/BasicTaintTracking.expected | 1 + .../test/library-tests/TaintTracking/xml.js | 3 +++ 3 files changed, 25 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll index de203a88f04..4a9c670ba37 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll @@ -226,6 +226,27 @@ module XML { } } + /** + * An invocation of `xml-js`. + */ + private class XmlJSInvocation extends XML::ParserInvocation { + XmlJSInvocation() { + this = + js::DataFlow::moduleMember("xml-js", ["xml2json", "xml2js", "json2xml", "js2xml"]) + .getACall() + .asExpr() + } + + override js::Expr getSourceArgument() { result = getArgument(0) } + + override predicate resolvesEntities(XML::EntityKind kind) { + // xml-js does not expand custom entities. + none() + } + + override js::DataFlow::Node getAResult() { result.asExpr() = this } + } + private class XMLParserTaintStep extends js::TaintTracking::AdditionalTaintStep { XML::ParserInvocation parser; diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index 39a370ecf71..ab48576b374 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -148,3 +148,4 @@ typeInferenceMismatch | xml.js:5:18:5:25 | source() | xml.js:8:14:8:17 | text | | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | +| xml.js:26:27:26:34 | source() | xml.js:26:10:26:39 | convert ... (), {}) | diff --git a/javascript/ql/test/library-tests/TaintTracking/xml.js b/javascript/ql/test/library-tests/TaintTracking/xml.js index a603f3d1c0e..44989e7a733 100644 --- a/javascript/ql/test/library-tests/TaintTracking/xml.js +++ b/javascript/ql/test/library-tests/TaintTracking/xml.js @@ -22,4 +22,7 @@ parser.write(source()).close(); + var convert = require('xml-js'); + sink(convert.xml2json(source(), {})); // NOT OK + })(); \ No newline at end of file From 0ca231059474c1535e3fd19898acb46dd463ff80 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 4 Feb 2021 18:26:24 +0100 Subject: [PATCH 269/429] add model for htmlparser2 --- .../javascript/frameworks/XmlParsers.qll | 29 +++++++++++++++++++ .../TaintTracking/BasicTaintTracking.expected | 1 + .../test/library-tests/TaintTracking/xml.js | 9 ++++++ 3 files changed, 39 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll index 4a9c670ba37..80c2ff8a608 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/XmlParsers.qll @@ -247,6 +247,35 @@ module XML { override js::DataFlow::Node getAResult() { result.asExpr() = this } } + /** + * An invocation of `htmlparser2`. + */ + private class HtmlParser2Invocation extends XML::ParserInvocation { + js::DataFlow::NewNode parser; + + HtmlParser2Invocation() { + parser = js::DataFlow::moduleMember("htmlparser2", "Parser").getAnInstantiation() and + this = parser.getAMemberCall("write").asExpr() + } + + override js::Expr getSourceArgument() { result = getArgument(0) } + + override predicate resolvesEntities(XML::EntityKind kind) { + // htmlparser2 does not expand entities. + none() + } + + override js::DataFlow::Node getAResult() { + result = + parser + .getArgument(0) + .getALocalSource() + .getAPropertySource() + .getAFunctionValue() + .getAParameter() + } + } + private class XMLParserTaintStep extends js::TaintTracking::AdditionalTaintStep { XML::ParserInvocation parser; diff --git a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected index ab48576b374..c98e9ad7e79 100644 --- a/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected +++ b/javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected @@ -149,3 +149,4 @@ typeInferenceMismatch | xml.js:12:17:12:24 | source() | xml.js:13:14:13:19 | result | | xml.js:23:18:23:25 | source() | xml.js:20:14:20:17 | attr | | xml.js:26:27:26:34 | source() | xml.js:26:10:26:39 | convert ... (), {}) | +| xml.js:34:18:34:25 | source() | xml.js:31:18:31:21 | name | diff --git a/javascript/ql/test/library-tests/TaintTracking/xml.js b/javascript/ql/test/library-tests/TaintTracking/xml.js index 44989e7a733..8e3785d4a2b 100644 --- a/javascript/ql/test/library-tests/TaintTracking/xml.js +++ b/javascript/ql/test/library-tests/TaintTracking/xml.js @@ -25,4 +25,13 @@ var convert = require('xml-js'); sink(convert.xml2json(source(), {})); // NOT OK + const htmlparser2 = require("htmlparser2"); + const parser = new htmlparser2.Parser({ + onopentag(name, attributes) { + sink(name) // NOT OK + } + }); + parser.write(source()); + parser.end(); + })(); \ No newline at end of file From 4969a1ef4fee604b4eca05aab08f32f6333904de Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 17:34:36 +0100 Subject: [PATCH 270/429] add change note --- javascript/change-notes/2021-02-08-xml-parser-taint.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 javascript/change-notes/2021-02-08-xml-parser-taint.md diff --git a/javascript/change-notes/2021-02-08-xml-parser-taint.md b/javascript/change-notes/2021-02-08-xml-parser-taint.md new file mode 100644 index 00000000000..ab59b4f3b92 --- /dev/null +++ b/javascript/change-notes/2021-02-08-xml-parser-taint.md @@ -0,0 +1,8 @@ +lgtm,codescanning +* The security queries now track taint through XML parsers. + Affected packages are + [xml2js](https://www.npmjs.com/package/xml2js) and + [sax](https://www.npmjs.com/package/sax) and + [xml-js](https://www.npmjs.com/package/xml-js) and + [htmlparser2](https://www.npmjs.com/package/htmlparser2) and + [node-expat](https://www.npmjs.com/package/node-expat) From d1087d4e41a017558daa46be2ffb1f471200ca6d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sat, 6 Feb 2021 23:24:33 +0100 Subject: [PATCH 271/429] move sources from XssThroughDom into a customizations file --- .../security/dataflow/XssThroughDom.qll | 86 +--------------- .../dataflow/XssThroughDomCustomizations.qll | 99 +++++++++++++++++++ 2 files changed, 100 insertions(+), 85 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll index 8c3157fcce4..f0f3c9d973c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDom.qll @@ -11,8 +11,8 @@ private import semmle.javascript.dataflow.InferredTypes */ module XssThroughDom { import Xss::XssThroughDom + private import XssThroughDomCustomizations::XssThroughDom private import semmle.javascript.security.dataflow.Xss::DomBasedXss as DomBasedXss - private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery /** @@ -40,88 +40,4 @@ module XssThroughDom { DomBasedXss::isOptionallySanitizedEdge(pred, succ) } } - - /** - * Gets an attribute name that could store user-controlled data. - * - * Attributes such as "id", "href", and "src" are often used as input to HTML. - * However, they are either rarely controlable by a user, or already a sink for other XSS vulnerabilities. - * Such attributes are therefore ignored. - */ - bindingset[result] - string unsafeAttributeName() { - result.regexpMatch("data-.*") or - result.regexpMatch("aria-.*") or - result = ["name", "value", "title", "alt"] - } - - /** - * A source for text from the DOM from a JQuery method call. - */ - class JQueryTextSource extends Source, JQuery::MethodCall { - JQueryTextSource() { - ( - this.getMethodName() = ["text", "val"] and this.getNumArgument() = 0 - or - this.getMethodName() = "attr" and - this.getNumArgument() = 1 and - forex(InferredType t | t = this.getArgument(0).analyze().getAType() | t = TTString()) and - this.getArgument(0).mayHaveStringValue(unsafeAttributeName()) - ) and - // looks like a $("

    " + ... ) source, which is benign for this query. - not exists(DataFlow::Node prefix | - DomBasedXss::isPrefixOfJQueryHtmlString(this.getReceiver() - .(DataFlow::CallNode) - .getAnArgument(), prefix) - | - prefix.getStringValue().regexpMatch("\\s*<.*") - ) - } - } - - /** - * A source for text from the DOM from a DOM property read or call to `getAttribute()`. - */ - class DOMTextSource extends Source { - DOMTextSource() { - exists(DataFlow::PropRead read | read = this | - read.getBase().getALocalSource() = DOM::domValueRef() and - read.mayHavePropertyName(["innerText", "textContent", "value", "name"]) - ) - or - exists(DataFlow::MethodCallNode mcn | mcn = this | - mcn.getReceiver().getALocalSource() = DOM::domValueRef() and - mcn.getMethodName() = "getAttribute" and - mcn.getArgument(0).mayHaveStringValue(unsafeAttributeName()) - ) - } - } - - /** - * A test of form `typeof x === "something"`, preventing `x` from being a string in some cases. - * - * This sanitizer helps prune infeasible paths in type-overloaded functions. - */ - class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode { - override EqualityTest astNode; - Expr operand; - boolean polarity; - - TypeTestGuard() { - exists(TypeofTag tag | TaintTracking::isTypeofGuard(astNode, operand, tag) | - // typeof x === "string" sanitizes `x` when it evaluates to false - tag = "string" and - polarity = astNode.getPolarity().booleanNot() - or - // typeof x === "object" sanitizes `x` when it evaluates to true - tag != "string" and - polarity = astNode.getPolarity() - ) - } - - override predicate sanitizes(boolean outcome, Expr e) { - polarity = outcome and - e = operand - } - } } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll new file mode 100644 index 00000000000..3b7a774de3f --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll @@ -0,0 +1,99 @@ +/** + * Provides default sources for reasoning about + * cross-site scripting vulnerabilities through the DOM. + */ + +import javascript + +/** + * Sources for cross-site scripting vulnerabilities through the DOM. + */ +module XssThroughDom { + import Xss::XssThroughDom + private import semmle.javascript.dataflow.InferredTypes + private import semmle.javascript.security.dataflow.Xss::DomBasedXss as DomBasedXss + + /** + * Gets an attribute name that could store user-controlled data. + * + * Attributes such as "id", "href", and "src" are often used as input to HTML. + * However, they are either rarely controlable by a user, or already a sink for other XSS vulnerabilities. + * Such attributes are therefore ignored. + */ + bindingset[result] + string unsafeAttributeName() { + result.regexpMatch("data-.*") or + result.regexpMatch("aria-.*") or + result = ["name", "value", "title", "alt"] + } + + /** + * A source for text from the DOM from a JQuery method call. + */ + class JQueryTextSource extends Source, JQuery::MethodCall { + JQueryTextSource() { + ( + this.getMethodName() = ["text", "val"] and this.getNumArgument() = 0 + or + this.getMethodName() = "attr" and + this.getNumArgument() = 1 and + forex(InferredType t | t = this.getArgument(0).analyze().getAType() | t = TTString()) and + this.getArgument(0).mayHaveStringValue(unsafeAttributeName()) + ) and + // looks like a $("

    " + ... ) source, which is benign for this query. + not exists(DataFlow::Node prefix | + DomBasedXss::isPrefixOfJQueryHtmlString(this.getReceiver() + .(DataFlow::CallNode) + .getAnArgument(), prefix) + | + prefix.getStringValue().regexpMatch("\\s*<.*") + ) + } + } + + /** + * A source for text from the DOM from a DOM property read or call to `getAttribute()`. + */ + class DOMTextSource extends Source { + DOMTextSource() { + exists(DataFlow::PropRead read | read = this | + read.getBase().getALocalSource() = DOM::domValueRef() and + read.mayHavePropertyName(["innerText", "textContent", "value", "name"]) + ) + or + exists(DataFlow::MethodCallNode mcn | mcn = this | + mcn.getReceiver().getALocalSource() = DOM::domValueRef() and + mcn.getMethodName() = "getAttribute" and + mcn.getArgument(0).mayHaveStringValue(unsafeAttributeName()) + ) + } + } + + /** + * A test of form `typeof x === "something"`, preventing `x` from being a string in some cases. + * + * This sanitizer helps prune infeasible paths in type-overloaded functions. + */ + class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode { + override EqualityTest astNode; + Expr operand; + boolean polarity; + + TypeTestGuard() { + exists(TypeofTag tag | TaintTracking::isTypeofGuard(astNode, operand, tag) | + // typeof x === "string" sanitizes `x` when it evaluates to false + tag = "string" and + polarity = astNode.getPolarity().booleanNot() + or + // typeof x === "object" sanitizes `x` when it evaluates to true + tag != "string" and + polarity = astNode.getPolarity() + ) + } + + override predicate sanitizes(boolean outcome, Expr e) { + polarity = outcome and + e = operand + } + } +} From ff3950ce98023d8db4c2beadd39a3b66501d8746 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sun, 7 Feb 2021 12:58:10 +0100 Subject: [PATCH 272/429] add model for formik --- .../dataflow/XssThroughDomCustomizations.qll | 41 +++++++++++++++ .../XssThroughDom/XssThroughDom.expected | 52 +++++++++++++++++++ .../Security/CWE-079/XssThroughDom/forms.js | 39 ++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll index 3b7a774de3f..8990f69aa0d 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll @@ -96,4 +96,45 @@ module XssThroughDom { e = operand } } + + /** + * A module for form inputs seen as sources for xss-through-dom. + */ + module Forms { + /** + * A reference to an import of `Formik`. + */ + private DataFlow::SourceNode formik() { + result = DataFlow::moduleImport("formik") + or + result = DataFlow::globalVarRef("Formik") + } + + /** + * An object containing input values from a form build with `Formik`. + */ + class FormikSource extends Source { + FormikSource() { + exists(JSXElement elem | + formik().getAPropertyRead("Formik").flowsToExpr(elem.getNameExpr()) + | + this = + elem.getAttributeByName(["validate", "onSubmit"]) + .getValue() + .flow() + .getAFunctionValue() + .getParameter(0) + ) + or + this = + formik() + .getAMemberCall("withFormik") + .getOptionArgument(0, ["validate", "handleSubmit"]) + .getAFunctionValue() + .getParameter(0) + or + this = formik().getAMemberCall("useFormikContext").getAPropertyRead("values") + } + } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index ae003b99243..5c938cd6c1d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -1,4 +1,30 @@ nodes +| forms.js:8:23:8:28 | values | +| forms.js:8:23:8:28 | values | +| forms.js:9:31:9:36 | values | +| forms.js:9:31:9:40 | values.foo | +| forms.js:9:31:9:40 | values.foo | +| forms.js:11:24:11:29 | values | +| forms.js:11:24:11:29 | values | +| forms.js:12:31:12:36 | values | +| forms.js:12:31:12:40 | values.bar | +| forms.js:12:31:12:40 | values.bar | +| forms.js:24:15:24:20 | values | +| forms.js:24:15:24:20 | values | +| forms.js:25:23:25:28 | values | +| forms.js:25:23:25:34 | values.email | +| forms.js:25:23:25:34 | values.email | +| forms.js:28:20:28:25 | values | +| forms.js:28:20:28:25 | values | +| forms.js:29:23:29:28 | values | +| forms.js:29:23:29:34 | values.email | +| forms.js:29:23:29:34 | values.email | +| forms.js:34:11:34:53 | values | +| forms.js:34:13:34:18 | values | +| forms.js:34:13:34:18 | values | +| forms.js:35:19:35:24 | values | +| forms.js:35:19:35:30 | values.email | +| forms.js:35:19:35:30 | values.email | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | @@ -50,6 +76,27 @@ nodes | xss-through-dom.js:79:4:79:34 | documen ... t.value | | xss-through-dom.js:79:4:79:34 | documen ... t.value | edges +| forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values | +| forms.js:8:23:8:28 | values | forms.js:9:31:9:36 | values | +| forms.js:9:31:9:36 | values | forms.js:9:31:9:40 | values.foo | +| forms.js:9:31:9:36 | values | forms.js:9:31:9:40 | values.foo | +| forms.js:11:24:11:29 | values | forms.js:12:31:12:36 | values | +| forms.js:11:24:11:29 | values | forms.js:12:31:12:36 | values | +| forms.js:12:31:12:36 | values | forms.js:12:31:12:40 | values.bar | +| forms.js:12:31:12:36 | values | forms.js:12:31:12:40 | values.bar | +| forms.js:24:15:24:20 | values | forms.js:25:23:25:28 | values | +| forms.js:24:15:24:20 | values | forms.js:25:23:25:28 | values | +| forms.js:25:23:25:28 | values | forms.js:25:23:25:34 | values.email | +| forms.js:25:23:25:28 | values | forms.js:25:23:25:34 | values.email | +| forms.js:28:20:28:25 | values | forms.js:29:23:29:28 | values | +| forms.js:28:20:28:25 | values | forms.js:29:23:29:28 | values | +| forms.js:29:23:29:28 | values | forms.js:29:23:29:34 | values.email | +| forms.js:29:23:29:28 | values | forms.js:29:23:29:34 | values.email | +| forms.js:34:11:34:53 | values | forms.js:35:19:35:24 | values | +| forms.js:34:13:34:18 | values | forms.js:34:11:34:53 | values | +| forms.js:34:13:34:18 | values | forms.js:34:11:34:53 | values | +| forms.js:35:19:35:24 | values | forms.js:35:19:35:30 | values.email | +| forms.js:35:19:35:24 | values | forms.js:35:19:35:30 | values.email | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | @@ -70,6 +117,11 @@ edges | xss-through-dom.js:73:20:73:41 | $("inpu ... 0).name | xss-through-dom.js:73:9:73:41 | selector | | xss-through-dom.js:79:4:79:34 | documen ... t.value | xss-through-dom.js:79:4:79:34 | documen ... t.value | #select +| forms.js:9:31:9:40 | values.foo | forms.js:8:23:8:28 | values | forms.js:9:31:9:40 | values.foo | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:8:23:8:28 | values | DOM text | +| forms.js:12:31:12:40 | values.bar | forms.js:11:24:11:29 | values | forms.js:12:31:12:40 | values.bar | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:11:24:11:29 | values | DOM text | +| forms.js:25:23:25:34 | values.email | forms.js:24:15:24:20 | values | forms.js:25:23:25:34 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:24:15:24:20 | values | DOM text | +| forms.js:29:23:29:34 | values.email | forms.js:28:20:28:25 | values | forms.js:29:23:29:34 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:28:20:28:25 | values | DOM text | +| forms.js:35:19:35:30 | values.email | forms.js:34:13:34:18 | values | forms.js:35:19:35:30 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:34:13:34:18 | values | DOM text | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js new file mode 100644 index 00000000000..2159c424dfe --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { Formik, withFormik, useFormikContext } from 'formik'; + +const FormikBasic = () => ( +

    + { + $("#id").html(values.foo); // NOT OK + }} + onSubmit={(values, { setSubmitting }) => { + $("#id").html(values.bar); // NOT OK + }} + > + {(inputs) => ( +
    + )} +
    +
    +); + +const FormikEnhanced = withFormik({ + mapPropsToValues: () => ({ name: '' }), + validate: values => { + $("#id").html(values.email); // NOT OK + }, + + handleSubmit: (values, { setSubmitting }) => { + $("#id").html(values.email); // NOT OK + } +})(MyForm); + +(function () { + const { values, submitForm } = useFormikContext(); + $("#id").html(values.email); // NOT OK + + $("#id").html(submitForm.email); // OK +}) + From 458dda9d2571f16048abee1f96d6e0bde26afa2f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Sun, 7 Feb 2021 22:47:57 +0100 Subject: [PATCH 273/429] add xss-through-dom source from react-final-form --- .../dataflow/XssThroughDomCustomizations.qll | 18 ++++++++++++++++++ .../XssThroughDom/XssThroughDom.expected | 10 ++++++++++ .../Security/CWE-079/XssThroughDom/forms.js | 15 +++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll index 8990f69aa0d..ada7412f8cb 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll @@ -136,5 +136,23 @@ module XssThroughDom { this = formik().getAMemberCall("useFormikContext").getAPropertyRead("values") } } + + /** + * An object containing input values from a form build with `react-final-form`. + */ + class ReactFinalFormSource extends Source { + ReactFinalFormSource() { + exists(JSXElement elem | + DataFlow::moduleMember("react-final-form", "Form").flowsToExpr(elem.getNameExpr()) + | + this = + elem.getAttributeByName("onSubmit") + .getValue() + .flow() + .getAFunctionValue() + .getParameter(0) + ) + } + } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index 5c938cd6c1d..b7621d89ab7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -25,6 +25,11 @@ nodes | forms.js:35:19:35:24 | values | | forms.js:35:19:35:30 | values.email | | forms.js:35:19:35:30 | values.email | +| forms.js:44:21:44:26 | values | +| forms.js:44:21:44:26 | values | +| forms.js:45:21:45:26 | values | +| forms.js:45:21:45:33 | values.stooge | +| forms.js:45:21:45:33 | values.stooge | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | @@ -97,6 +102,10 @@ edges | forms.js:34:13:34:18 | values | forms.js:34:11:34:53 | values | | forms.js:35:19:35:24 | values | forms.js:35:19:35:30 | values.email | | forms.js:35:19:35:24 | values | forms.js:35:19:35:30 | values.email | +| forms.js:44:21:44:26 | values | forms.js:45:21:45:26 | values | +| forms.js:44:21:44:26 | values | forms.js:45:21:45:26 | values | +| forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge | +| forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | @@ -122,6 +131,7 @@ edges | forms.js:25:23:25:34 | values.email | forms.js:24:15:24:20 | values | forms.js:25:23:25:34 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:24:15:24:20 | values | DOM text | | forms.js:29:23:29:34 | values.email | forms.js:28:20:28:25 | values | forms.js:29:23:29:34 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:28:20:28:25 | values | DOM text | | forms.js:35:19:35:30 | values.email | forms.js:34:13:34:18 | values | forms.js:35:19:35:30 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:34:13:34:18 | values | DOM text | +| forms.js:45:21:45:33 | values.stooge | forms.js:44:21:44:26 | values | forms.js:45:21:45:33 | values.stooge | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:44:21:44:26 | values | DOM text | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js index 2159c424dfe..7054b8333d7 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js @@ -37,3 +37,18 @@ const FormikEnhanced = withFormik({ $("#id").html(submitForm.email); // OK }) +import { Form } from 'react-final-form' + +const App = () => ( +
    { + $("#id").html(values.stooge); // NOT OK + }} + initialValues={{ stooge: 'larry', employed: false }} + render={({ handleSubmit, form, submitting, pristine, values }) => ( + + +
    + )} + /> +) \ No newline at end of file From 65d93c9061193e576c7f980a6c2c21dd70b6b1d4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 09:36:11 +0100 Subject: [PATCH 274/429] detect for DOM elements from DOM events in React --- javascript/ql/src/semmle/javascript/DOM.qll | 13 +++++++++++++ .../CWE-079/XssThroughDom/XssThroughDom.expected | 5 +++++ .../Security/CWE-079/XssThroughDom/forms.js | 11 +++++++++++ 3 files changed, 29 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index a1facf39505..e5a3d3eb672 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -357,6 +357,15 @@ module DOM { } } + /** + * Gets a reference to a DOM event. + */ + private DataFlow::SourceNode domEventSource() { + exists(JSXAttribute attr | attr.getName().matches("on%") | + result = attr.getValue().flow().getABoundFunctionValue(0).getParameter(0) + ) + } + /** Gets a data flow node that refers directly to a value from the DOM. */ DataFlow::SourceNode domValueSource() { result instanceof DomValueSource::Range } @@ -368,6 +377,10 @@ module DOM { t.start() and result = domValueRef().getAMethodCall(["item", "namedItem"]) or + // e.g.
    e.target}/> + t.startInProp("target") and + result = domEventSource() + or exists(DataFlow::TypeTracker t2 | result = domValueRef(t2).track(t2, t)) } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index b7621d89ab7..dfe5365f5d1 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -30,6 +30,9 @@ nodes | forms.js:45:21:45:26 | values | | forms.js:45:21:45:33 | values.stooge | | forms.js:45:21:45:33 | values.stooge | +| forms.js:57:19:57:32 | e.target.value | +| forms.js:57:19:57:32 | e.target.value | +| forms.js:57:19:57:32 | e.target.value | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | @@ -106,6 +109,7 @@ edges | forms.js:44:21:44:26 | values | forms.js:45:21:45:26 | values | | forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge | | forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge | +| forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | @@ -132,6 +136,7 @@ edges | forms.js:29:23:29:34 | values.email | forms.js:28:20:28:25 | values | forms.js:29:23:29:34 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:28:20:28:25 | values | DOM text | | forms.js:35:19:35:30 | values.email | forms.js:34:13:34:18 | values | forms.js:35:19:35:30 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:34:13:34:18 | values | DOM text | | forms.js:45:21:45:33 | values.stooge | forms.js:44:21:44:26 | values | forms.js:45:21:45:33 | values.stooge | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:44:21:44:26 | values | DOM text | +| forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:57:19:57:32 | e.target.value | DOM text | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js index 7054b8333d7..84ebb26e088 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js @@ -51,4 +51,15 @@ const App = () => (
    )} /> +); + +function plainSubmit(e) { + $("#id").html(e.target.value); // NOT OK +} + +const plainReact = () => ( +
    plainSubmit(e)}> + + +
    ) \ No newline at end of file From be9636491bf996d02abb63a9666f61a5763ef880 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 15:44:34 +0100 Subject: [PATCH 275/429] add source for react-hook-form in xss-through-dom --- .../dataflow/XssThroughDomCustomizations.qll | 16 ++++++++ .../XssThroughDom/XssThroughDom.expected | 22 +++++++++++ .../Security/CWE-079/XssThroughDom/forms.js | 37 ++++++++++++++++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll index ada7412f8cb..2176d5f83c6 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/XssThroughDomCustomizations.qll @@ -154,5 +154,21 @@ module XssThroughDom { ) } } + + /** + * An object containing input values from a form build with `react-hook-form`. + */ + class ReactHookFormSource extends Source { + ReactHookFormSource() { + exists(API::Node useForm | + useForm = API::moduleImport("react-hook-form").getMember("useForm").getReturn() + | + this = + useForm.getMember("handleSubmit").getParameter(0).getParameter(0).getAnImmediateUse() + or + this = useForm.getMember("getValues").getACall() + ) + } + } } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index dfe5365f5d1..8fc40dc01e6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -33,6 +33,17 @@ nodes | forms.js:57:19:57:32 | e.target.value | | forms.js:57:19:57:32 | e.target.value | | forms.js:57:19:57:32 | e.target.value | +| forms.js:71:21:71:24 | data | +| forms.js:71:21:71:24 | data | +| forms.js:72:19:72:22 | data | +| forms.js:72:19:72:27 | data.name | +| forms.js:72:19:72:27 | data.name | +| forms.js:92:17:92:36 | values | +| forms.js:92:26:92:36 | getValues() | +| forms.js:92:26:92:36 | getValues() | +| forms.js:93:25:93:30 | values | +| forms.js:93:25:93:35 | values.name | +| forms.js:93:25:93:35 | values.name | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | @@ -110,6 +121,15 @@ edges | forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge | | forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge | | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | +| forms.js:71:21:71:24 | data | forms.js:72:19:72:22 | data | +| forms.js:71:21:71:24 | data | forms.js:72:19:72:22 | data | +| forms.js:72:19:72:22 | data | forms.js:72:19:72:27 | data.name | +| forms.js:72:19:72:22 | data | forms.js:72:19:72:27 | data.name | +| forms.js:92:17:92:36 | values | forms.js:93:25:93:30 | values | +| forms.js:92:26:92:36 | getValues() | forms.js:92:17:92:36 | values | +| forms.js:92:26:92:36 | getValues() | forms.js:92:17:92:36 | values | +| forms.js:93:25:93:30 | values | forms.js:93:25:93:35 | values.name | +| forms.js:93:25:93:30 | values | forms.js:93:25:93:35 | values.name | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | @@ -137,6 +157,8 @@ edges | forms.js:35:19:35:30 | values.email | forms.js:34:13:34:18 | values | forms.js:35:19:35:30 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:34:13:34:18 | values | DOM text | | forms.js:45:21:45:33 | values.stooge | forms.js:44:21:44:26 | values | forms.js:45:21:45:33 | values.stooge | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:44:21:44:26 | values | DOM text | | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:57:19:57:32 | e.target.value | DOM text | +| forms.js:72:19:72:27 | data.name | forms.js:71:21:71:24 | data | forms.js:72:19:72:27 | data.name | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:71:21:71:24 | data | DOM text | +| forms.js:93:25:93:35 | values.name | forms.js:92:26:92:36 | getValues() | forms.js:93:25:93:35 | values.name | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:92:26:92:36 | getValues() | DOM text | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js index 84ebb26e088..4c84701d241 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js @@ -62,4 +62,39 @@ const plainReact = () => ( -) \ No newline at end of file +) + +import { useForm } from 'react-hook-form'; + +function HookForm() { + const { register, handleSubmit, errors } = useForm(); // initialize the hook + const onSubmit = (data) => { + $("#id").html(data.name); // NOT OK + }; + + return ( +
    + + +
    + ); +} + +function HookForm2() { + const { register, getValues } = useForm(); + + return ( +
    + + +
    + ); +} + \ No newline at end of file From 101d4358a9f334d39ae954291f968079d19805d3 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 16:00:50 +0100 Subject: [PATCH 276/429] detect DOM nodes from event callbacks --- javascript/ql/src/semmle/javascript/DOM.qll | 11 ++++++++++- .../CWE-079/XssThroughDom/XssThroughDom.expected | 10 ++++++++++ .../Security/CWE-079/XssThroughDom/forms.js | 11 ++++++++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index e5a3d3eb672..5b1b9c30542 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -361,9 +361,19 @@ module DOM { * Gets a reference to a DOM event. */ private DataFlow::SourceNode domEventSource() { + // e.g.
    e.target}/> exists(JSXAttribute attr | attr.getName().matches("on%") | result = attr.getValue().flow().getABoundFunctionValue(0).getParameter(0) ) + or + // node.addEventListener("submit", e => e.target) + result = domValueRef().getAMethodCall("addEventListener").getABoundCallbackParameter(1, 0) + or + // node.onSubmit = (e => e.target); + exists(DataFlow::PropWrite write | write = domValueRef().getAPropertyWrite() | + write.getPropertyName().matches("on%") and + result = write.getRhs().getAFunctionValue().getParameter(0) + ) } /** Gets a data flow node that refers directly to a value from the DOM. */ @@ -377,7 +387,6 @@ module DOM { t.start() and result = domValueRef().getAMethodCall(["item", "namedItem"]) or - // e.g. e.target}/> t.startInProp("target") and result = domEventSource() or diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected index 8fc40dc01e6..cfa5ba99070 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/XssThroughDom.expected @@ -44,6 +44,12 @@ nodes | forms.js:93:25:93:30 | values | | forms.js:93:25:93:35 | values.name | | forms.js:93:25:93:35 | values.name | +| forms.js:103:23:103:36 | e.target.value | +| forms.js:103:23:103:36 | e.target.value | +| forms.js:103:23:103:36 | e.target.value | +| forms.js:107:23:107:36 | e.target.value | +| forms.js:107:23:107:36 | e.target.value | +| forms.js:107:23:107:36 | e.target.value | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | @@ -130,6 +136,8 @@ edges | forms.js:92:26:92:36 | getValues() | forms.js:92:17:92:36 | values | | forms.js:93:25:93:30 | values | forms.js:93:25:93:35 | values.name | | forms.js:93:25:93:30 | values | forms.js:93:25:93:35 | values.name | +| forms.js:103:23:103:36 | e.target.value | forms.js:103:23:103:36 | e.target.value | +| forms.js:107:23:107:36 | e.target.value | forms.js:107:23:107:36 | e.target.value | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | @@ -159,6 +167,8 @@ edges | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:57:19:57:32 | e.target.value | DOM text | | forms.js:72:19:72:27 | data.name | forms.js:71:21:71:24 | data | forms.js:72:19:72:27 | data.name | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:71:21:71:24 | data | DOM text | | forms.js:93:25:93:35 | values.name | forms.js:92:26:92:36 | getValues() | forms.js:93:25:93:35 | values.name | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:92:26:92:36 | getValues() | DOM text | +| forms.js:103:23:103:36 | e.target.value | forms.js:103:23:103:36 | e.target.value | forms.js:103:23:103:36 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:103:23:103:36 | e.target.value | DOM text | +| forms.js:107:23:107:36 | e.target.value | forms.js:107:23:107:36 | e.target.value | forms.js:107:23:107:36 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:107:23:107:36 | e.target.value | DOM text | | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text | | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text | | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js index 4c84701d241..b91b7490bb2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js @@ -97,4 +97,13 @@ function HookForm2() {
    ); } - \ No newline at end of file + +function vanillaJS() { + document.querySelector("form.myform").addEventListener("submit", e => { + $("#id").html(e.target.value); // NOT OK + }); + + document.querySelector("form.myform").onsubmit = function (e) { + $("#id").html(e.target.value); // NOT OK + } +} \ No newline at end of file From 91f7d330448bbb67de31e4d839bea7c3b78463db Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 17:31:47 +0100 Subject: [PATCH 277/429] add change note --- javascript/change-notes/2021-02-08-xss-through-dom-forms.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/change-notes/2021-02-08-xss-through-dom-forms.md diff --git a/javascript/change-notes/2021-02-08-xss-through-dom-forms.md b/javascript/change-notes/2021-02-08-xss-through-dom-forms.md new file mode 100644 index 00000000000..33c864bbaef --- /dev/null +++ b/javascript/change-notes/2021-02-08-xss-through-dom-forms.md @@ -0,0 +1,6 @@ +lgtm,codescanning +* The `js/xss-through-dom` query now recognizes form inputs as sources. + Affected packages are + [formik](https://www.npmjs.com/package/formik) and + [react-final-form](https://www.npmjs.com/package/react-final-form) and + [react-hook-form](https://www.npmjs.com/package/react-hook-form) From b4704f70160d222de2a71eaa55828de86be59c99 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 10 Feb 2021 14:51:08 +0100 Subject: [PATCH 278/429] add taint-step for the `marked` library --- javascript/ql/src/javascript.qll | 1 + .../semmle/javascript/frameworks/Markdown.qll | 21 +++++++++++++++++++ .../ReflectedXss/ReflectedXss.expected | 14 +++++++++++++ .../CWE-079/ReflectedXss/ReflectedXss.js | 6 ++++++ .../ReflectedXssWithCustomSanitizer.expected | 2 ++ 5 files changed, 44 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/Markdown.qll diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index d5c459c4d5c..9b035508497 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -93,6 +93,7 @@ import semmle.javascript.frameworks.LazyCache import semmle.javascript.frameworks.LodashUnderscore import semmle.javascript.frameworks.Logging import semmle.javascript.frameworks.HttpFrameworks +import semmle.javascript.frameworks.Markdown import semmle.javascript.frameworks.NoSQL import semmle.javascript.frameworks.PkgCloud import semmle.javascript.frameworks.PropertyProjection diff --git a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll new file mode 100644 index 00000000000..c32c7189c7c --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll @@ -0,0 +1,21 @@ +/** + * Provides classes for modelling common markdown parsers and generators. + */ + +import javascript + +/** + * A taint step for the `marked` library, that converts markdown to HTML. + */ +private class MarkedStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode { + MarkedStep() { + this = DataFlow::globalVarRef("marked").getACall() + or + this = DataFlow::moduleImport("marked").getACall() + } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + succ = this and + pred = this.getAnArgument() + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected index bc28be8d730..32878144f34 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected @@ -7,6 +7,13 @@ nodes | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | | ReflectedXss.js:17:31:17:39 | params.id | | ReflectedXss.js:17:31:17:39 | params.id | +| ReflectedXss.js:22:12:22:19 | req.body | +| ReflectedXss.js:22:12:22:19 | req.body | +| ReflectedXss.js:22:12:22:19 | req.body | +| ReflectedXss.js:23:12:23:27 | marked(req.body) | +| ReflectedXss.js:23:12:23:27 | marked(req.body) | +| ReflectedXss.js:23:19:23:26 | req.body | +| ReflectedXss.js:23:19:23:26 | req.body | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | @@ -100,6 +107,11 @@ edges | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | +| ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | +| ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | +| ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | +| ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | +| ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | @@ -178,6 +190,8 @@ edges #select | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | ReflectedXss.js:8:33:8:45 | req.params.id | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value | +| ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:22:12:22:19 | req.body | user-provided value | +| ReflectedXss.js:23:12:23:27 | marked(req.body) | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js index 4a7c04a989c..68e8a5057a6 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js @@ -16,3 +16,9 @@ app.get('/user/:id', function(req, res) { function moreBadStuff(params, res) { res.send("Unknown user: " + params.id); // NOT OK } + +var marked = require("marked"); +app.get('/user/:id', function(req, res) { + res.send(req.body); // NOT OK + res.send(marked(req.body)); // NOT OK +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected index b35bbd53c1b..d1e58db0ecb 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected @@ -1,5 +1,7 @@ | ReflectedXss.js:8:14:8:45 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:8:33:8:45 | req.params.id | user-provided value | | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value | +| ReflectedXss.js:22:12:22:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:22:12:22:19 | req.body | user-provided value | +| ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | From f76018c039f125c6258e30a2aae4a7bc4d30c7cf Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 10 Feb 2021 15:11:41 +0100 Subject: [PATCH 279/429] add taint step for the `markdown-table` library --- .../semmle/javascript/frameworks/Markdown.qll | 14 ++++++++++++- .../ReflectedXss/ReflectedXss.expected | 21 +++++++++++++++++++ .../CWE-079/ReflectedXss/ReflectedXss.js | 11 ++++++++++ .../ReflectedXssWithCustomSanitizer.expected | 2 ++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll index c32c7189c7c..55949202a82 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll @@ -16,6 +16,18 @@ private class MarkedStep extends TaintTracking::AdditionalTaintStep, DataFlow::C override predicate step(DataFlow::Node pred, DataFlow::Node succ) { succ = this and - pred = this.getAnArgument() + pred = this.getArgument(0) + } +} + +/** + * A taint step for the `markdown-table` library. + */ +private class MarkdownTableStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode { + MarkdownTableStep() { this = DataFlow::moduleImport("markdown-table").getACall() } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + succ = this and + pred = this.getArgument(0) } } diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected index 32878144f34..a6413502bf8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected @@ -14,6 +14,17 @@ nodes | ReflectedXss.js:23:12:23:27 | marked(req.body) | | ReflectedXss.js:23:19:23:26 | req.body | | ReflectedXss.js:23:19:23:26 | req.body | +| ReflectedXss.js:29:12:29:19 | req.body | +| ReflectedXss.js:29:12:29:19 | req.body | +| ReflectedXss.js:29:12:29:19 | req.body | +| ReflectedXss.js:30:7:33:4 | mytable | +| ReflectedXss.js:30:17:33:4 | table([ ... y]\\n ]) | +| ReflectedXss.js:30:23:33:3 | [\\n [ ... dy]\\n ] | +| ReflectedXss.js:32:5:32:22 | ['body', req.body] | +| ReflectedXss.js:32:14:32:21 | req.body | +| ReflectedXss.js:32:14:32:21 | req.body | +| ReflectedXss.js:34:12:34:18 | mytable | +| ReflectedXss.js:34:12:34:18 | mytable | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | @@ -112,6 +123,14 @@ edges | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | +| ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | +| ReflectedXss.js:30:7:33:4 | mytable | ReflectedXss.js:34:12:34:18 | mytable | +| ReflectedXss.js:30:7:33:4 | mytable | ReflectedXss.js:34:12:34:18 | mytable | +| ReflectedXss.js:30:17:33:4 | table([ ... y]\\n ]) | ReflectedXss.js:30:7:33:4 | mytable | +| ReflectedXss.js:30:23:33:3 | [\\n [ ... dy]\\n ] | ReflectedXss.js:30:17:33:4 | table([ ... y]\\n ]) | +| ReflectedXss.js:32:5:32:22 | ['body', req.body] | ReflectedXss.js:30:23:33:3 | [\\n [ ... dy]\\n ] | +| ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:32:5:32:22 | ['body', req.body] | +| ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:32:5:32:22 | ['body', req.body] | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | @@ -192,6 +211,8 @@ edges | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | ReflectedXss.js:17:31:17:39 | params.id | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value | | ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | ReflectedXss.js:22:12:22:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:22:12:22:19 | req.body | user-provided value | | ReflectedXss.js:23:12:23:27 | marked(req.body) | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | +| ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:29:12:29:19 | req.body | user-provided value | +| ReflectedXss.js:34:12:34:18 | mytable | ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js index 68e8a5057a6..bcef58877ba 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js @@ -22,3 +22,14 @@ app.get('/user/:id', function(req, res) { res.send(req.body); // NOT OK res.send(marked(req.body)); // NOT OK }); + + +var table = require('markdown-table') +app.get('/user/:id', function(req, res) { + res.send(req.body); // NOT OK + var mytable = table([ + ['Name', 'Content'], + ['body', req.body] + ]); + res.send(mytable); // NOT OK +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected index d1e58db0ecb..ce0cec4cce5 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected @@ -2,6 +2,8 @@ | ReflectedXss.js:17:12:17:39 | "Unknow ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:17:31:17:39 | params.id | user-provided value | | ReflectedXss.js:22:12:22:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:22:12:22:19 | req.body | user-provided value | | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | +| ReflectedXss.js:29:12:29:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:29:12:29:19 | req.body | user-provided value | +| ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | From 42eceb80bd1f038a584e9f52f146e78e89f944ba Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 10 Feb 2021 15:47:55 +0100 Subject: [PATCH 280/429] Python: Handle view functions with decorators --- ...-21-django-view-function-with-decorator.md | 2 ++ .../src/semmle/python/frameworks/Django.qll | 21 ++++++++++++++++++- .../frameworks/django-v2-v3/routing_test.py | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 python/change-notes/2021-12-21-django-view-function-with-decorator.md diff --git a/python/change-notes/2021-12-21-django-view-function-with-decorator.md b/python/change-notes/2021-12-21-django-view-function-with-decorator.md new file mode 100644 index 00000000000..404ce23f240 --- /dev/null +++ b/python/change-notes/2021-12-21-django-view-function-with-decorator.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Improved modeling of `django` to recognize request handlers functions that are decorated (for example with `django.views.decorators.http.require_GET`). This leads to more sources of remote user input (`RemoteFlowSource`), since we correctly identify the first parameter as being passed a django request. diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index fd43d938806..b39edb6d97c 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -1975,6 +1975,14 @@ private module Django { } } + /** + * Gets the last decorator call for the function `func`, if `func` has decorators. + */ + private Expr lastDecoratorCall(Function func) { + result = func.getDefinition().(FunctionExpr).getADecoratorCall() and + not exists(Call other_decorator | other_decorator.getArg(0) = result) + } + // --------------------------------------------------------------------------- // routing modeling // --------------------------------------------------------------------------- @@ -1987,7 +1995,18 @@ private module Django { */ private DataFlow::Node djangoRouteHandlerFunctionTracker(DataFlow::TypeTracker t, Function func) { t.start() and - result = DataFlow::exprNode(func.getDefinition()) + ( + not exists(func.getADecorator()) and + result.asExpr() = func.getDefinition() + or + // If the function has decorators, we still want to model the function as being + // the request handler for a route setup. In such situations, we must track the + // last decorator call instead of the function itself. + // + // Note that this means that we blindly ignore what the decorator actually does to + // the function, which seems like an OK tradeoff. + result.asExpr() = lastDecoratorCall(func) + ) or exists(DataFlow::TypeTracker t2 | result = djangoRouteHandlerFunctionTracker(t2, func).track(t2, t) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index d6736433b0f..c45c4a36869 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -134,7 +134,7 @@ class PossiblyNotRouted(View): @require_GET -def with_decorator(request, foo): # $ MISSING: requestHandler routedParameter=foo +def with_decorator(request, foo): # $ requestHandler routedParameter=foo pass urlpatterns = [ From 78a3206fce88d07157404ab5e045941d4465057a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 10 Feb 2021 15:55:54 +0100 Subject: [PATCH 281/429] Python: Add test with unkown view class in django --- .../frameworks/django-v2-v3/routing_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index c45c4a36869..557201a8d65 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -140,3 +140,13 @@ def with_decorator(request, foo): # $ requestHandler routedParameter=foo urlpatterns = [ path("with_decorator/", with_decorator), # $ routeSetup="with_decorator/" ] + +class UnknownViewSubclass(UnknownViewSuperclass): + # Although we don't know for certain that this class is a django view class, the fact that it's + # used with `as_view()` in the routing setup should be enough that we treat it as such. + def get(self, request): # $ MISSING: requestHandler + pass + +urlpatterns = [ + path("UnknownViewSubclass/", UnknownViewSubclass.as_view()), # $ routeSetup="UnknownViewSubclass/" +] From b428945bc296d2a9a8f798fe600e48da89e19221 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 10 Feb 2021 16:06:44 +0100 Subject: [PATCH 282/429] Django: Fix DjangoRouteHandler char-pred Before it the class would contain _all_ functions xD --- python/ql/src/semmle/python/frameworks/Django.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index b39edb6d97c..08794a32a89 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2029,7 +2029,7 @@ private module Django { DjangoViewClassDef() { this.getABase() = django::views::generic::View::subclassRef().asExpr() } /** Gets a function that could handle incoming requests, if any. */ - DjangoRouteHandler getARequestHandler() { + Function getARequestHandler() { // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def result = this.getAMethod() and @@ -2076,7 +2076,7 @@ private module Django { */ private class DjangoRouteHandler extends Function { DjangoRouteHandler() { - exists(djangoRouteHandlerFunctionTracker(this)) + exists(DjangoRouteSetup route | route.getViewArg() = djangoRouteHandlerFunctionTracker(this)) or any(DjangoViewClassDef vc).getARequestHandler() = this } From ca0d3459875dc505f98611bf3915d7f195c5cb12 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 10 Feb 2021 16:26:25 +0100 Subject: [PATCH 283/429] Django: Model any class used in django route setup as view class --- ...r.md => 2021-12-21-django-improvements.md} | 1 + .../src/semmle/python/frameworks/Django.qll | 51 +++++++++++++------ .../frameworks/django-v2-v3/routing_test.py | 2 +- 3 files changed, 38 insertions(+), 16 deletions(-) rename python/change-notes/{2021-12-21-django-view-function-with-decorator.md => 2021-12-21-django-improvements.md} (52%) diff --git a/python/change-notes/2021-12-21-django-view-function-with-decorator.md b/python/change-notes/2021-12-21-django-improvements.md similarity index 52% rename from python/change-notes/2021-12-21-django-view-function-with-decorator.md rename to python/change-notes/2021-12-21-django-improvements.md index 404ce23f240..e3a22961c73 100644 --- a/python/change-notes/2021-12-21-django-view-function-with-decorator.md +++ b/python/change-notes/2021-12-21-django-improvements.md @@ -1,2 +1,3 @@ lgtm,codescanning * Improved modeling of `django` to recognize request handlers functions that are decorated (for example with `django.views.decorators.http.require_GET`). This leads to more sources of remote user input (`RemoteFlowSource`), since we correctly identify the first parameter as being passed a django request. +* Improved modeling of django View classes. We now consider any class using in a routing setup with `.as_view()` as django view class. This leads to more sources of remote user input (`RemoteFlowSource`), since we correctly identify the first parameter as being passed a django request. diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 08794a32a89..6599ccdc03a 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2024,18 +2024,8 @@ private module Django { result = djangoRouteHandlerFunctionTracker(DataFlow::TypeTracker::end(), func) } - /** A django View class defined in project code. */ - class DjangoViewClassDef extends Class { - DjangoViewClassDef() { this.getABase() = django::views::generic::View::subclassRef().asExpr() } - - /** Gets a function that could handle incoming requests, if any. */ - Function getARequestHandler() { - // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with - // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def - result = this.getAMethod() and - result.getName() = HTTP::httpVerbLower() - } - + /** A class that might be a django View class. */ + class PossibleDjangoViewClass extends Class { /** Gets a reference to this class. */ private DataFlow::Node getARef(DataFlow::TypeTracker t) { t.start() and @@ -2070,6 +2060,37 @@ private module Django { DataFlow::Node asViewResult() { result = asViewResult(DataFlow::TypeTracker::end()) } } + /** A class that we consider a django View class. */ + abstract class DjangoViewClass extends PossibleDjangoViewClass { + /** Gets a function that could handle incoming requests, if any. */ + Function getARequestHandler() { + // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with + // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def + result = this.getAMethod() and + result.getName() = HTTP::httpVerbLower() + } + } + + /** + * A class that is used in a route-setup, with `.as_view()`, therefore being + * considered a django View class. + */ + class DjangoViewClassFromRouteSetup extends DjangoViewClass { + DjangoViewClassFromRouteSetup() { + exists(DjangoRouteSetup setup | setup.getViewArg() = this.asViewResult()) + } + } + + /** + * A class that has a super-type which is a django View class, therefore also + * becoming a django View class. + */ + class DjangoViewClassFromSuperClass extends DjangoViewClass { + DjangoViewClassFromSuperClass() { + this.getABase() = django::views::generic::View::subclassRef().asExpr() + } + } + /** * A function that is a django route handler, meaning it handles incoming requests * with the django framework. @@ -2078,7 +2099,7 @@ private module Django { DjangoRouteHandler() { exists(DjangoRouteSetup route | route.getViewArg() = djangoRouteHandlerFunctionTracker(this)) or - any(DjangoViewClassDef vc).getARequestHandler() = this + any(DjangoViewClass vc).getARequestHandler() = this } /** Gets the index of the request parameter. */ @@ -2102,7 +2123,7 @@ private module Django { final override DjangoRouteHandler getARequestHandler() { djangoRouteHandlerFunctionTracker(result) = getViewArg() or - exists(DjangoViewClassDef vc | + exists(DjangoViewClass vc | getViewArg() = vc.asViewResult() and result = vc.getARequestHandler() ) @@ -2113,7 +2134,7 @@ private module Django { private class DjangoViewClassHandlerWithoutKnownRoute extends HTTP::Server::RequestHandler::Range, DjangoRouteHandler { DjangoViewClassHandlerWithoutKnownRoute() { - exists(DjangoViewClassDef vc | vc.getARequestHandler() = this) and + exists(DjangoViewClass vc | vc.getARequestHandler() = this) and not exists(DjangoRouteSetup setup | setup.getARequestHandler() = this) } diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py index 557201a8d65..acdbe2cfa42 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/routing_test.py @@ -144,7 +144,7 @@ urlpatterns = [ class UnknownViewSubclass(UnknownViewSuperclass): # Although we don't know for certain that this class is a django view class, the fact that it's # used with `as_view()` in the routing setup should be enough that we treat it as such. - def get(self, request): # $ MISSING: requestHandler + def get(self, request): # $ requestHandler pass urlpatterns = [ From 0d497e8b9af1c2d2d970d198fddaede34caf7de6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 10 Feb 2021 17:22:35 +0100 Subject: [PATCH 284/429] add model for the `showdown` library --- .../semmle/javascript/frameworks/Markdown.qll | 17 +++++++++++++++++ .../CWE-079/ReflectedXss/ReflectedXss.expected | 14 ++++++++++++++ .../CWE-079/ReflectedXss/ReflectedXss.js | 8 ++++++++ .../ReflectedXssWithCustomSanitizer.expected | 2 ++ 4 files changed, 41 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll index 55949202a82..ed902bb9274 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll @@ -31,3 +31,20 @@ private class MarkdownTableStep extends TaintTracking::AdditionalTaintStep, Data pred = this.getArgument(0) } } + +/** + * A taint step for the `showdown` library. + */ +private class ShowDownStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode { + ShowDownStep() { + this = + [DataFlow::globalVarRef("showdown"), DataFlow::moduleImport("showdown")] + .getAConstructorInvocation("Converter") + .getAMemberCall(["makeHtml", "makeMd"]) + } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + succ = this and + pred = this.getArgument(0) + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected index a6413502bf8..38661c86c6d 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected @@ -25,6 +25,13 @@ nodes | ReflectedXss.js:32:14:32:21 | req.body | | ReflectedXss.js:34:12:34:18 | mytable | | ReflectedXss.js:34:12:34:18 | mytable | +| ReflectedXss.js:41:12:41:19 | req.body | +| ReflectedXss.js:41:12:41:19 | req.body | +| ReflectedXss.js:41:12:41:19 | req.body | +| ReflectedXss.js:42:12:42:39 | convert ... q.body) | +| ReflectedXss.js:42:12:42:39 | convert ... q.body) | +| ReflectedXss.js:42:31:42:38 | req.body | +| ReflectedXss.js:42:31:42:38 | req.body | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | @@ -131,6 +138,11 @@ edges | ReflectedXss.js:32:5:32:22 | ['body', req.body] | ReflectedXss.js:30:23:33:3 | [\\n [ ... dy]\\n ] | | ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:32:5:32:22 | ['body', req.body] | | ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:32:5:32:22 | ['body', req.body] | +| ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | +| ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | +| ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | +| ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | +| ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | @@ -213,6 +225,8 @@ edges | ReflectedXss.js:23:12:23:27 | marked(req.body) | ReflectedXss.js:23:19:23:26 | req.body | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | | ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | ReflectedXss.js:29:12:29:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:29:12:29:19 | req.body | user-provided value | | ReflectedXss.js:34:12:34:18 | mytable | ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | +| ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:41:12:41:19 | req.body | user-provided value | +| ReflectedXss.js:42:12:42:39 | convert ... q.body) | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:42:31:42:38 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js index bcef58877ba..e9461f2c6d8 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js @@ -33,3 +33,11 @@ app.get('/user/:id', function(req, res) { ]); res.send(mytable); // NOT OK }); + +var showdown = require('showdown'); +var converter = new showdown.Converter(); + +app.get('/user/:id', function(req, res) { + res.send(req.body); // NOT OK + res.send(converter.makeHtml(req.body)); // NOT OK +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected index ce0cec4cce5..ddd7ae3b372 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected @@ -4,6 +4,8 @@ | ReflectedXss.js:23:12:23:27 | marked(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:23:19:23:26 | req.body | user-provided value | | ReflectedXss.js:29:12:29:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:29:12:29:19 | req.body | user-provided value | | ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | +| ReflectedXss.js:41:12:41:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:41:12:41:19 | req.body | user-provided value | +| ReflectedXss.js:42:12:42:39 | convert ... q.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:42:31:42:38 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | From 9ca738d921d2ea570dcb4037f2bf3543925fda56 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 10 Feb 2021 16:37:57 +0100 Subject: [PATCH 285/429] Python: Add taint test for self.request on django view class --- .../django-v2-v3/TestTaint.expected | 160 +++++++++--------- .../frameworks/django-v2-v3/taint_test.py | 18 +- .../frameworks/django-v2-v3/testapp/views.py | 1 + 3 files changed, 101 insertions(+), 78 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected index 97037cb1079..d3cb5470b1b 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected @@ -1,82 +1,88 @@ -| taint_test.py:7 | ok | test_taint | bar | -| taint_test.py:7 | ok | test_taint | foo | -| taint_test.py:8 | ok | test_taint | baz | -| taint_test.py:14 | ok | test_taint | request | -| taint_test.py:16 | ok | test_taint | request.body | -| taint_test.py:17 | ok | test_taint | request.path | -| taint_test.py:18 | ok | test_taint | request.path_info | -| taint_test.py:22 | ok | test_taint | request.method | -| taint_test.py:24 | ok | test_taint | request.encoding | -| taint_test.py:25 | ok | test_taint | request.content_type | -| taint_test.py:28 | ok | test_taint | request.content_params | -| taint_test.py:29 | ok | test_taint | request.content_params["key"] | -| taint_test.py:30 | ok | test_taint | request.content_params.get(..) | -| taint_test.py:34 | ok | test_taint | request.GET | -| taint_test.py:35 | ok | test_taint | request.GET["key"] | -| taint_test.py:36 | ok | test_taint | request.GET.get(..) | -| taint_test.py:37 | fail | test_taint | request.GET.getlist(..) | -| taint_test.py:38 | fail | test_taint | request.GET.getlist(..)[0] | -| taint_test.py:39 | ok | test_taint | request.GET.pop(..) | -| taint_test.py:40 | ok | test_taint | request.GET.pop(..)[0] | -| taint_test.py:41 | ok | test_taint | request.GET.popitem()[0] | -| taint_test.py:42 | ok | test_taint | request.GET.popitem()[1] | -| taint_test.py:43 | ok | test_taint | request.GET.popitem()[1][0] | -| taint_test.py:44 | fail | test_taint | request.GET.dict() | -| taint_test.py:45 | fail | test_taint | request.GET.dict()["key"] | -| taint_test.py:46 | fail | test_taint | request.GET.urlencode() | -| taint_test.py:49 | ok | test_taint | request.POST | -| taint_test.py:52 | ok | test_taint | request.COOKIES | -| taint_test.py:53 | ok | test_taint | request.COOKIES["key"] | -| taint_test.py:54 | ok | test_taint | request.COOKIES.get(..) | -| taint_test.py:57 | ok | test_taint | request.FILES | -| taint_test.py:58 | ok | test_taint | request.FILES["key"] | -| taint_test.py:59 | fail | test_taint | request.FILES["key"].content_type | -| taint_test.py:60 | fail | test_taint | request.FILES["key"].content_type_extra | -| taint_test.py:61 | fail | test_taint | request.FILES["key"].content_type_extra["key"] | -| taint_test.py:62 | fail | test_taint | request.FILES["key"].charset | -| taint_test.py:63 | fail | test_taint | request.FILES["key"].name | -| taint_test.py:64 | fail | test_taint | request.FILES["key"].file | -| taint_test.py:65 | fail | test_taint | request.FILES["key"].file.read() | -| taint_test.py:67 | ok | test_taint | request.FILES.get(..) | -| taint_test.py:68 | fail | test_taint | request.FILES.get(..).name | -| taint_test.py:69 | fail | test_taint | request.FILES.getlist(..) | -| taint_test.py:70 | fail | test_taint | request.FILES.getlist(..)[0] | -| taint_test.py:71 | fail | test_taint | request.FILES.getlist(..)[0].name | -| taint_test.py:72 | fail | test_taint | request.FILES.dict() | -| taint_test.py:73 | fail | test_taint | request.FILES.dict()["key"] | -| taint_test.py:74 | fail | test_taint | request.FILES.dict()["key"].name | -| taint_test.py:77 | ok | test_taint | request.META | -| taint_test.py:78 | ok | test_taint | request.META["HTTP_USER_AGENT"] | -| taint_test.py:79 | ok | test_taint | request.META.get(..) | -| taint_test.py:82 | ok | test_taint | request.headers | -| taint_test.py:83 | ok | test_taint | request.headers["user-agent"] | -| taint_test.py:84 | ok | test_taint | request.headers["USER_AGENT"] | -| taint_test.py:87 | ok | test_taint | request.resolver_match | -| taint_test.py:88 | fail | test_taint | request.resolver_match.args | -| taint_test.py:89 | fail | test_taint | request.resolver_match.args[0] | -| taint_test.py:90 | fail | test_taint | request.resolver_match.kwargs | -| taint_test.py:91 | fail | test_taint | request.resolver_match.kwargs["key"] | -| taint_test.py:93 | fail | test_taint | request.get_full_path() | -| taint_test.py:94 | fail | test_taint | request.get_full_path_info() | -| taint_test.py:98 | fail | test_taint | request.read() | -| taint_test.py:99 | fail | test_taint | request.readline() | -| taint_test.py:100 | fail | test_taint | request.readlines() | -| taint_test.py:101 | fail | test_taint | request.readlines()[0] | -| taint_test.py:102 | fail | test_taint | ListComp | -| taint_test.py:108 | ok | test_taint | args | -| taint_test.py:109 | ok | test_taint | args[0] | -| taint_test.py:110 | ok | test_taint | kwargs | -| taint_test.py:111 | ok | test_taint | kwargs["key"] | -| taint_test.py:115 | ok | test_taint | request.current_app | -| taint_test.py:120 | ok | test_taint | request.get_host() | -| taint_test.py:121 | ok | test_taint | request.get_port() | -| taint_test.py:128 | fail | test_taint | request.build_absolute_uri() | -| taint_test.py:129 | fail | test_taint | request.build_absolute_uri(..) | +| taint_test.py:8 | ok | test_taint | bar | +| taint_test.py:8 | ok | test_taint | foo | +| taint_test.py:9 | ok | test_taint | baz | +| taint_test.py:15 | ok | test_taint | request | +| taint_test.py:17 | ok | test_taint | request.body | +| taint_test.py:18 | ok | test_taint | request.path | +| taint_test.py:19 | ok | test_taint | request.path_info | +| taint_test.py:23 | ok | test_taint | request.method | +| taint_test.py:25 | ok | test_taint | request.encoding | +| taint_test.py:26 | ok | test_taint | request.content_type | +| taint_test.py:29 | ok | test_taint | request.content_params | +| taint_test.py:30 | ok | test_taint | request.content_params["key"] | +| taint_test.py:31 | ok | test_taint | request.content_params.get(..) | +| taint_test.py:35 | ok | test_taint | request.GET | +| taint_test.py:36 | ok | test_taint | request.GET["key"] | +| taint_test.py:37 | ok | test_taint | request.GET.get(..) | +| taint_test.py:38 | fail | test_taint | request.GET.getlist(..) | +| taint_test.py:39 | fail | test_taint | request.GET.getlist(..)[0] | +| taint_test.py:40 | ok | test_taint | request.GET.pop(..) | +| taint_test.py:41 | ok | test_taint | request.GET.pop(..)[0] | +| taint_test.py:42 | ok | test_taint | request.GET.popitem()[0] | +| taint_test.py:43 | ok | test_taint | request.GET.popitem()[1] | +| taint_test.py:44 | ok | test_taint | request.GET.popitem()[1][0] | +| taint_test.py:45 | fail | test_taint | request.GET.dict() | +| taint_test.py:46 | fail | test_taint | request.GET.dict()["key"] | +| taint_test.py:47 | fail | test_taint | request.GET.urlencode() | +| taint_test.py:50 | ok | test_taint | request.POST | +| taint_test.py:53 | ok | test_taint | request.COOKIES | +| taint_test.py:54 | ok | test_taint | request.COOKIES["key"] | +| taint_test.py:55 | ok | test_taint | request.COOKIES.get(..) | +| taint_test.py:58 | ok | test_taint | request.FILES | +| taint_test.py:59 | ok | test_taint | request.FILES["key"] | +| taint_test.py:60 | fail | test_taint | request.FILES["key"].content_type | +| taint_test.py:61 | fail | test_taint | request.FILES["key"].content_type_extra | +| taint_test.py:62 | fail | test_taint | request.FILES["key"].content_type_extra["key"] | +| taint_test.py:63 | fail | test_taint | request.FILES["key"].charset | +| taint_test.py:64 | fail | test_taint | request.FILES["key"].name | +| taint_test.py:65 | fail | test_taint | request.FILES["key"].file | +| taint_test.py:66 | fail | test_taint | request.FILES["key"].file.read() | +| taint_test.py:68 | ok | test_taint | request.FILES.get(..) | +| taint_test.py:69 | fail | test_taint | request.FILES.get(..).name | +| taint_test.py:70 | fail | test_taint | request.FILES.getlist(..) | +| taint_test.py:71 | fail | test_taint | request.FILES.getlist(..)[0] | +| taint_test.py:72 | fail | test_taint | request.FILES.getlist(..)[0].name | +| taint_test.py:73 | fail | test_taint | request.FILES.dict() | +| taint_test.py:74 | fail | test_taint | request.FILES.dict()["key"] | +| taint_test.py:75 | fail | test_taint | request.FILES.dict()["key"].name | +| taint_test.py:78 | ok | test_taint | request.META | +| taint_test.py:79 | ok | test_taint | request.META["HTTP_USER_AGENT"] | +| taint_test.py:80 | ok | test_taint | request.META.get(..) | +| taint_test.py:83 | ok | test_taint | request.headers | +| taint_test.py:84 | ok | test_taint | request.headers["user-agent"] | +| taint_test.py:85 | ok | test_taint | request.headers["USER_AGENT"] | +| taint_test.py:88 | ok | test_taint | request.resolver_match | +| taint_test.py:89 | fail | test_taint | request.resolver_match.args | +| taint_test.py:90 | fail | test_taint | request.resolver_match.args[0] | +| taint_test.py:91 | fail | test_taint | request.resolver_match.kwargs | +| taint_test.py:92 | fail | test_taint | request.resolver_match.kwargs["key"] | +| taint_test.py:94 | fail | test_taint | request.get_full_path() | +| taint_test.py:95 | fail | test_taint | request.get_full_path_info() | +| taint_test.py:99 | fail | test_taint | request.read() | +| taint_test.py:100 | fail | test_taint | request.readline() | +| taint_test.py:101 | fail | test_taint | request.readlines() | +| taint_test.py:102 | fail | test_taint | request.readlines()[0] | +| taint_test.py:103 | fail | test_taint | ListComp | +| taint_test.py:109 | ok | test_taint | args | +| taint_test.py:110 | ok | test_taint | args[0] | +| taint_test.py:111 | ok | test_taint | kwargs | +| taint_test.py:112 | ok | test_taint | kwargs["key"] | +| taint_test.py:116 | ok | test_taint | request.current_app | +| taint_test.py:121 | ok | test_taint | request.get_host() | +| taint_test.py:122 | ok | test_taint | request.get_port() | +| taint_test.py:129 | fail | test_taint | request.build_absolute_uri() | | taint_test.py:130 | fail | test_taint | request.build_absolute_uri(..) | -| taint_test.py:133 | ok | test_taint | request.build_absolute_uri(..) | +| taint_test.py:131 | fail | test_taint | request.build_absolute_uri(..) | | taint_test.py:134 | ok | test_taint | request.build_absolute_uri(..) | -| taint_test.py:142 | ok | test_taint | request.get_signed_cookie(..) | +| taint_test.py:135 | ok | test_taint | request.build_absolute_uri(..) | | taint_test.py:143 | ok | test_taint | request.get_signed_cookie(..) | | taint_test.py:144 | ok | test_taint | request.get_signed_cookie(..) | -| taint_test.py:148 | fail | test_taint | request.get_signed_cookie(..) | +| taint_test.py:145 | ok | test_taint | request.get_signed_cookie(..) | | taint_test.py:149 | fail | test_taint | request.get_signed_cookie(..) | +| taint_test.py:150 | fail | test_taint | request.get_signed_cookie(..) | +| taint_test.py:157 | fail | some_method | self.request | +| taint_test.py:158 | fail | some_method | self.request.GET["key"] | +| taint_test.py:160 | fail | some_method | self.args | +| taint_test.py:161 | fail | some_method | self.args[0] | +| taint_test.py:163 | fail | some_method | self.kwargs | +| taint_test.py:164 | fail | some_method | self.kwargs["key"] | diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py index a0db86f2961..9c21e59e2e3 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/taint_test.py @@ -1,6 +1,7 @@ """testing views for Django 2.x and 3.x""" from django.urls import path from django.http import HttpRequest +from django.views import View def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler routedParameter=foo routedParameter=bar @@ -150,7 +151,22 @@ def test_taint(request: HttpRequest, foo, bar, baz=None): # $requestHandler rou ) +class ClassView(View): + def some_method(self): + ensure_tainted( + self.request, + self.request.GET["key"], + + self.args, + self.args[0], + + self.kwargs, + self.kwargs["key"], + ) + + # fake setup, you can't actually run this urlpatterns = [ - path("test-taint//", test_taint), # $routeSetup="test-taint//" + path("test-taint//", test_taint), # $ routeSetup="test-taint//" + path("ClassView/", ClassView.as_view()), # $ routeSetup="ClassView/" ] diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py index 55c60a551a0..d2028d0dd03 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py @@ -30,4 +30,5 @@ class MyCustomViewBaseClass(View): class MyViewHandlerWithCustomInheritance(MyCustomViewBaseClass): def get(self, request: HttpRequest): # $ requestHandler + print(self.request.GET) return HttpResponse("MyViewHandlerWithCustomInheritance: GET") # $ HttpResponse From c57a4df819f7c0450a060e1a627a0eeb71ee3223 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 10 Feb 2021 17:46:05 +0100 Subject: [PATCH 286/429] Python: Model taint of self.request on django view class --- .../2021-12-21-django-improvements.md | 1 + .../src/semmle/python/frameworks/Django.qll | 63 +++++++++++++++++++ .../django-v2-v3/TestTaint.expected | 12 ++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/python/change-notes/2021-12-21-django-improvements.md b/python/change-notes/2021-12-21-django-improvements.md index e3a22961c73..fb2e7494983 100644 --- a/python/change-notes/2021-12-21-django-improvements.md +++ b/python/change-notes/2021-12-21-django-improvements.md @@ -1,3 +1,4 @@ lgtm,codescanning * Improved modeling of `django` to recognize request handlers functions that are decorated (for example with `django.views.decorators.http.require_GET`). This leads to more sources of remote user input (`RemoteFlowSource`), since we correctly identify the first parameter as being passed a django request. * Improved modeling of django View classes. We now consider any class using in a routing setup with `.as_view()` as django view class. This leads to more sources of remote user input (`RemoteFlowSource`), since we correctly identify the first parameter as being passed a django request. +* Improved modeling of `django`, so for View classes we now model `self.request`, `self.args`, and `self.kwargs` as sources of remote user input (`RemoteFlowSource`). diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 6599ccdc03a..fee806ff8ef 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2069,6 +2069,29 @@ private module Django { result = this.getAMethod() and result.getName() = HTTP::httpVerbLower() } + + /** + * Gets a reference to instances of this class, originating from a self parameter of + * a method defined on this class. + * + * Note: TODO: This doesn't take MRO into account + * Note: TODO: This doesn't take staticmethod/classmethod into account + */ + private DataFlow::Node getASelfRef(DataFlow::TypeTracker t) { + t.start() and + result.(DataFlow::ParameterNode).getParameter() = this.getAMethod().getArg(0) + or + exists(DataFlow::TypeTracker t2 | result = this.getASelfRef(t2).track(t2, t)) + } + + /** + * Gets a reference to instances of this class, originating from a self parameter of + * a method defined on this class. + * + * Note: TODO: This doesn't take MRO into account + * Note: TODO: This doesn't take staticmethod/classmethod into account + */ + DataFlow::Node getASelfRef() { result = this.getASelfRef(DataFlow::TypeTracker::end()) } } /** @@ -2307,6 +2330,46 @@ private module Django { override string getSourceType() { result = "django.http.request.HttpRequest" } } + /** + * A read of the `request` attribute on a reference to an instance of a View class, + * which is the request being processed currently. + * + * See https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering + */ + private class DjangoViewClassRequestAttributeRead extends django::http::request::HttpRequest::InstanceSource, + RemoteFlowSource::Range, DataFlow::Node { + DjangoViewClassRequestAttributeRead() { + exists(DataFlow::AttrRead read | this = read | + read.getObject() = any(DjangoViewClass vc).getASelfRef() and + read.getAttributeName() = "request" + ) + } + + override string getSourceType() { + result = "django.http.request.HttpRequest (attribute on self in View class)" + } + } + + /** + * A read of the `args` or `kwargs` attribute on a reference to an instance of a View class, + * which contains the routed parameters captured from the URL route. + * + * See https://docs.djangoproject.com/en/3.1/topics/class-based-views/generic-display/#dynamic-filtering + */ + private class DjangoViewClassRoutedParamsAttributeRead extends RemoteFlowSource::Range, + DataFlow::Node { + DjangoViewClassRoutedParamsAttributeRead() { + exists(DataFlow::AttrRead read | this = read | + read.getObject() = any(DjangoViewClass vc).getASelfRef() and + read.getAttributeName() in ["args", "kwargs"] + ) + } + + override string getSourceType() { + result = "django routed param from attribute on self in View class" + } + } + private class DjangoHttpRequstAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { nodeFrom = django::http::request::HttpRequest::instance() and diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected index d3cb5470b1b..c76685c6739 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected @@ -80,9 +80,9 @@ | taint_test.py:145 | ok | test_taint | request.get_signed_cookie(..) | | taint_test.py:149 | fail | test_taint | request.get_signed_cookie(..) | | taint_test.py:150 | fail | test_taint | request.get_signed_cookie(..) | -| taint_test.py:157 | fail | some_method | self.request | -| taint_test.py:158 | fail | some_method | self.request.GET["key"] | -| taint_test.py:160 | fail | some_method | self.args | -| taint_test.py:161 | fail | some_method | self.args[0] | -| taint_test.py:163 | fail | some_method | self.kwargs | -| taint_test.py:164 | fail | some_method | self.kwargs["key"] | +| taint_test.py:157 | ok | some_method | self.request | +| taint_test.py:158 | ok | some_method | self.request.GET["key"] | +| taint_test.py:160 | ok | some_method | self.args | +| taint_test.py:161 | ok | some_method | self.args[0] | +| taint_test.py:163 | ok | some_method | self.kwargs | +| taint_test.py:164 | ok | some_method | self.kwargs["key"] | From 7cff1f441bef167d72f599693ed01937a613336c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 10 Feb 2021 18:13:01 +0100 Subject: [PATCH 287/429] add model for the `unified` and `remark` libraries --- .../semmle/javascript/frameworks/Markdown.qll | 58 +++++++++++++++++++ .../ReflectedXss/ReflectedXss.expected | 45 ++++++++++++++ .../CWE-079/ReflectedXss/ReflectedXss.js | 34 +++++++++++ .../ReflectedXssWithCustomSanitizer.expected | 5 ++ 4 files changed, 142 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll index ed902bb9274..0ea930a3453 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll @@ -48,3 +48,61 @@ private class ShowDownStep extends TaintTracking::AdditionalTaintStep, DataFlow: pred = this.getArgument(0) } } + +/** + * Classes and predicates for modelling taint steps in `unified` and `remark`. + */ +private module Unified { + /** + * The creation of a parser from `unified`. + * The `remark` module is a shorthand that initializes `unified` with a markdown parser. + */ + DataFlow::CallNode unified() { result = DataFlow::moduleImport(["unified", "remark"]).getACall() } + + /** + * A chain of method calls that process an input with `unified`. + */ + class UnifiedChain extends DataFlow::CallNode { + DataFlow::CallNode root; + + UnifiedChain() { + root = unified() and + this = root.getAChainedMethodCall(["process", "processSync"]) + } + + /** + * Gets a plugin that is used in this chain. + */ + DataFlow::Node getAUsedPlugin() { result = root.getAChainedMethodCall("use").getArgument(0) } + + /** + * Gets the input that is processed. + */ + DataFlow::Node getInput() { result = getArgument(0) } + + /** + * Gets the processed output. + */ + DataFlow::Node getOutput() { + this.getCalleeName() = "process" and result = getABoundCallbackParameter(1, 1) + or + this.getCalleeName() = "processSync" and result = this + } + } + + /** + * A taint step for the `unified` library. + */ + class UnifiedStep extends TaintTracking::AdditionalTaintStep, UnifiedChain { + UnifiedStep() { + // sanitizer. Mostly looking for `rehype-sanitize`, but also other plugins with `sanitize` in their name. + not this.getAUsedPlugin().getALocalSource() = + DataFlow::moduleImport(any(string s | s.matches("%sanitize%"))) + } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + pred = getInput() and + succ = getOutput() + } + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected index 38661c86c6d..cc01ba98932 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected @@ -32,6 +32,29 @@ nodes | ReflectedXss.js:42:12:42:39 | convert ... q.body) | | ReflectedXss.js:42:31:42:38 | req.body | | ReflectedXss.js:42:31:42:38 | req.body | +| ReflectedXss.js:56:12:56:19 | req.body | +| ReflectedXss.js:56:12:56:19 | req.body | +| ReflectedXss.js:56:12:56:19 | req.body | +| ReflectedXss.js:64:14:64:21 | req.body | +| ReflectedXss.js:64:14:64:21 | req.body | +| ReflectedXss.js:64:39:64:42 | file | +| ReflectedXss.js:65:16:65:19 | file | +| ReflectedXss.js:65:16:65:19 | file | +| ReflectedXss.js:68:12:68:41 | remark( ... q.body) | +| ReflectedXss.js:68:12:68:52 | remark( ... tring() | +| ReflectedXss.js:68:12:68:52 | remark( ... tring() | +| ReflectedXss.js:68:33:68:40 | req.body | +| ReflectedXss.js:68:33:68:40 | req.body | +| ReflectedXss.js:72:12:72:56 | unified ... q.body) | +| ReflectedXss.js:72:12:72:65 | unified ... oString | +| ReflectedXss.js:72:12:72:65 | unified ... oString | +| ReflectedXss.js:72:48:72:55 | req.body | +| ReflectedXss.js:72:48:72:55 | req.body | +| ReflectedXss.js:74:20:74:27 | req.body | +| ReflectedXss.js:74:20:74:27 | req.body | +| ReflectedXss.js:74:34:74:34 | f | +| ReflectedXss.js:75:14:75:14 | f | +| ReflectedXss.js:75:14:75:14 | f | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | @@ -143,6 +166,23 @@ edges | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | +| ReflectedXss.js:56:12:56:19 | req.body | ReflectedXss.js:56:12:56:19 | req.body | +| ReflectedXss.js:64:14:64:21 | req.body | ReflectedXss.js:64:39:64:42 | file | +| ReflectedXss.js:64:14:64:21 | req.body | ReflectedXss.js:64:39:64:42 | file | +| ReflectedXss.js:64:39:64:42 | file | ReflectedXss.js:65:16:65:19 | file | +| ReflectedXss.js:64:39:64:42 | file | ReflectedXss.js:65:16:65:19 | file | +| ReflectedXss.js:68:12:68:41 | remark( ... q.body) | ReflectedXss.js:68:12:68:52 | remark( ... tring() | +| ReflectedXss.js:68:12:68:41 | remark( ... q.body) | ReflectedXss.js:68:12:68:52 | remark( ... tring() | +| ReflectedXss.js:68:33:68:40 | req.body | ReflectedXss.js:68:12:68:41 | remark( ... q.body) | +| ReflectedXss.js:68:33:68:40 | req.body | ReflectedXss.js:68:12:68:41 | remark( ... q.body) | +| ReflectedXss.js:72:12:72:56 | unified ... q.body) | ReflectedXss.js:72:12:72:65 | unified ... oString | +| ReflectedXss.js:72:12:72:56 | unified ... q.body) | ReflectedXss.js:72:12:72:65 | unified ... oString | +| ReflectedXss.js:72:48:72:55 | req.body | ReflectedXss.js:72:12:72:56 | unified ... q.body) | +| ReflectedXss.js:72:48:72:55 | req.body | ReflectedXss.js:72:12:72:56 | unified ... q.body) | +| ReflectedXss.js:74:20:74:27 | req.body | ReflectedXss.js:74:34:74:34 | f | +| ReflectedXss.js:74:20:74:27 | req.body | ReflectedXss.js:74:34:74:34 | f | +| ReflectedXss.js:74:34:74:34 | f | ReflectedXss.js:75:14:75:14 | f | +| ReflectedXss.js:74:34:74:34 | f | ReflectedXss.js:75:14:75:14 | f | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | @@ -227,6 +267,11 @@ edges | ReflectedXss.js:34:12:34:18 | mytable | ReflectedXss.js:32:14:32:21 | req.body | ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | | ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | ReflectedXss.js:41:12:41:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:41:12:41:19 | req.body | user-provided value | | ReflectedXss.js:42:12:42:39 | convert ... q.body) | ReflectedXss.js:42:31:42:38 | req.body | ReflectedXss.js:42:12:42:39 | convert ... q.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:42:31:42:38 | req.body | user-provided value | +| ReflectedXss.js:56:12:56:19 | req.body | ReflectedXss.js:56:12:56:19 | req.body | ReflectedXss.js:56:12:56:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:56:12:56:19 | req.body | user-provided value | +| ReflectedXss.js:65:16:65:19 | file | ReflectedXss.js:64:14:64:21 | req.body | ReflectedXss.js:65:16:65:19 | file | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:64:14:64:21 | req.body | user-provided value | +| ReflectedXss.js:68:12:68:52 | remark( ... tring() | ReflectedXss.js:68:33:68:40 | req.body | ReflectedXss.js:68:12:68:52 | remark( ... tring() | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:68:33:68:40 | req.body | user-provided value | +| ReflectedXss.js:72:12:72:65 | unified ... oString | ReflectedXss.js:72:48:72:55 | req.body | ReflectedXss.js:72:12:72:65 | unified ... oString | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:72:48:72:55 | req.body | user-provided value | +| ReflectedXss.js:75:14:75:14 | f | ReflectedXss.js:74:20:74:27 | req.body | ReflectedXss.js:75:14:75:14 | f | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:74:20:74:27 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js index e9461f2c6d8..15f8ea7f7fd 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js @@ -41,3 +41,37 @@ app.get('/user/:id', function(req, res) { res.send(req.body); // NOT OK res.send(converter.makeHtml(req.body)); // NOT OK }); + +var unified = require('unified'); +var markdown = require('remark-parse'); +var remark2rehype = require('remark-rehype'); +var doc = require('rehype-document'); +var format = require('rehype-format'); +var html = require('rehype-stringify'); +var remark = require("remark"); +var sanitize = require("rehype-sanitize"); +const { resetExtensions } = require('showdown'); + +app.get('/user/:id', function (req, res) { + res.send(req.body); // NOT OK + + unified() + .use(markdown) + .use(remark2rehype) + .use(doc, { title: '👋🌍' }) + .use(format) + .use(html) + .process(req.body, function (err, file) { + res.send(file); // NOT OK + }); + + res.send(remark().processSync(req.body).toString()); // NOT OK + + res.send(remark().use(sanitize).processSync(req.body).toString()); // OK + + res.send(unified().use(markdown).processSync(req.body).toString); // NOT OK + + remark().process(req.body, (e, f) => { + res.send(f); // NOT OK + }) +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected index ddd7ae3b372..96f1093be3b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected @@ -6,6 +6,11 @@ | ReflectedXss.js:34:12:34:18 | mytable | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:32:14:32:21 | req.body | user-provided value | | ReflectedXss.js:41:12:41:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:41:12:41:19 | req.body | user-provided value | | ReflectedXss.js:42:12:42:39 | convert ... q.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:42:31:42:38 | req.body | user-provided value | +| ReflectedXss.js:56:12:56:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:56:12:56:19 | req.body | user-provided value | +| ReflectedXss.js:65:16:65:19 | file | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:64:14:64:21 | req.body | user-provided value | +| ReflectedXss.js:68:12:68:52 | remark( ... tring() | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:68:33:68:40 | req.body | user-provided value | +| ReflectedXss.js:72:12:72:65 | unified ... oString | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:72:48:72:55 | req.body | user-provided value | +| ReflectedXss.js:75:14:75:14 | f | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:74:20:74:27 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | From 190164c182463c32226374975cb61b330db7a145 Mon Sep 17 00:00:00 2001 From: Raul Garcia <42392023+raulgarciamsft@users.noreply.github.com> Date: Wed, 10 Feb 2021 13:30:40 -0800 Subject: [PATCH 288/429] Update csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp Co-authored-by: Bas van Schaik <5082246+sj@users.noreply.github.com> --- .../Security Features/campaign/Solorigate/Solorigate.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp index dcd7c0b9d74..bba4df25c7d 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp @@ -4,10 +4,10 @@

    The nation-state supply chain attack on SolarWinds known as Solorigate or SunBurst gave nation-state actors access to some victims' networks.

    -

    The purpose of these rules is to identify potentially tampered code that requires further analysis

    +

    The purpose of these rules is to identify potentially tampered code that requires further analysis.

    Any findings from this rule are only intended to indicate suspicious code that shares similarities with known portions of code used for the Solorigate attack. There is no certainty that the code is related or that the code is part of any attack.

    For more information, please visit https://aka.ms/solorigate.

    -
    \ No newline at end of file + From ef0d3720a1010abaaa41b37308c5727e9d257849 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Wed, 10 Feb 2021 13:39:24 -0800 Subject: [PATCH 289/429] Addressing a few comments --- .../Security Features/backdoor/PotentialTimeBomb.qhelp | 2 +- .../campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp | 2 +- .../campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp index fb619cb738e..57a8c5719fa 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp +++ b/csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.qhelp @@ -3,7 +3,7 @@ "qhelp.dtd"> -

    This query checks for data flow from a file's last modification date and a condition statement that controls code execution. A malicious actor could have implanted code that triggers after a certain time, leading to a "time bomb".

    +

    This query detects situations in which an offset to a last file modification time is used to conditionally execute a particular block of code. This is a common pattern in backdoors, where the file's modification timestamp is the time at which the backdoor was planted, and the time offset is used as a time bomb before a particular code block is executed.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp index 8b639b14ab0..0b0e1333eb1 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp @@ -3,7 +3,7 @@ "qhelp.dtd"> -

    In Solorigate, the malicious code tried to evade various security detection software by comparing hashes of the process names against an embedded list of values. The malicious code included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by a literal after computing the FNV-1A.

    +

    In Solorigate, the malicious code tried to evade various security detection software by comparing hashes of the process names against an embedded list of values. The malicious code used in the SolarWinds attack included hash values calculated using a standard FNV-1A 64-bit hash with an additional XOR by a literal after computing the FNV-1A.

    This query detects FNV-like hash calculations where there is an additional XOR (with any static value) after the hash calculation loop.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql index 34c773636ad..42fb738f157 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.ql @@ -1,6 +1,6 @@ /** * @name Number of Solorigate-related command names in enum is above the threshold - * @description The enum contains several values that look similar to command and control command names, which may indicate that the code may have been tampered by an external agent. + * @description The enum contains several values that look similar to command and control command names, which may indicate that the code may have been tampered with by an external agent. * It is recommended to review the code and verify that there is no unexpected code in this project. * @kind problem * @tags security From 2a1c11b517d31cf20550eacc68656d3c7c1b1631 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 10 Feb 2021 23:56:45 +0100 Subject: [PATCH 290/429] Improve MavenPom documentation, rename inconsistent predicates --- java/ql/src/semmle/code/xml/MavenPom.qll | 96 +++++++++++++----------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/java/ql/src/semmle/code/xml/MavenPom.qll b/java/ql/src/semmle/code/xml/MavenPom.qll index 0a545c0bc99..30c1e673b23 100644 --- a/java/ql/src/semmle/code/xml/MavenPom.qll +++ b/java/ql/src/semmle/code/xml/MavenPom.qll @@ -28,7 +28,7 @@ class ProtoPom extends XMLElement { Version getVersion() { result = this.getAChild() } /** - * Gets a string representing the version, or an empty string if no version + * Gets a string representing the version, or an empty string if no `version` * tag was provided. */ string getVersionString() { @@ -53,7 +53,7 @@ class Pom extends ProtoPom { Pom() { this.getName() = "project" and // Ignore "dependency-reduced-pom" files - these are generated by the - // shading plugin, and duplicate existing pom files. + // Maven Shade Plugin, and duplicate existing POM files. this.getFile().getStem() != "dependency-reduced-pom" } @@ -77,7 +77,7 @@ class Pom extends ProtoPom { /** Gets a child XML element named "dependencies". */ Dependencies getDependencies() { result = this.getAChild() } - /** Gets a child XML element named `dependencyManagement`. */ + /** Gets a child XML element named "dependencyManagement". */ DependencyManagement getDependencyManagement() { result = getAChild() } /** Gets a Dependency element for this POM. */ @@ -100,7 +100,8 @@ class Pom extends ProtoPom { } /** - * Gets a property value defined for this project with the given name. + * Gets a property value defined for this project with the given name, either in a local + * `` section, or in the `` section of an ancestor POM. */ PomProperty getProperty(string name) { result.getName() = name and @@ -112,7 +113,7 @@ class Pom extends ProtoPom { */ PomElement getProjectProperty() { ( - // It must either be a child of the pom, or a child of the parent node of the pom + // It must either be a child of the POM, or a child of the parent node of the POM result = getAChild() or result = getParentPom().getAChild() and @@ -124,8 +125,8 @@ class Pom extends ProtoPom { } /** - * Resolve the given placeholder (if possible) in the static context of this pom. Resolution - * occurs by considering the properties defined by this project. + * Resolve the given placeholder (if possible) in the static context of this POM. Resolution + * occurs by considering the properties defined by this project or an ancestor project. */ string resolvePlaceholder(string name) { if name.prefix(8) = "project." @@ -142,32 +143,33 @@ class Pom extends ProtoPom { } /** - * Gets all the dependencies that are exported by this pom. An exported dependency is one that - * is transitively available, i.e. one with scope compile. + * Gets all the dependencies that are exported by this POM. An exported dependency is one that + * is transitively available, i.e. one with scope "compile". */ Dependency getAnExportedDependency() { result = getADependency() and result.getScope() = "compile" } /** - * Gets a pom dependency that is exported by this pom. An exported dependency is one that - * is transitively available, i.e. one with scope compile. + * Gets a POM dependency that is exported by this POM. An exported dependency is one that + * is transitively available, i.e. one with scope "compile". */ Pom getAnExportedPom() { result = getAnExportedDependency().getPom() } /** - * Gets the `` element of this pom, if any. + * Gets the `` element of this POM, if any. */ Parent getParentElement() { result = getAChild() } /** - * Gets the pom referred to by the `` element of this pom, if any. + * Gets the POM referred to by the `` element of this POM, if any. */ Pom getParentPom() { result = getParentElement().getPom() } /** - * Gets the version specified for dependency `dep` in a `dependencyManagement` - * section if this pom or one of its ancestors. + * Gets the version specified for dependency _dep_ in a `dependencyManagement` + * section in this POM or one of its ancestors, or an empty string if no version + * is specified. */ string getVersionStringForDependency(Dependency dep) { if exists(getDependencyManagement().getDependency(dep)) @@ -223,12 +225,13 @@ class Dependency extends ProtoPom { Pom getPom() { result.getShortCoordinate() = this.getShortCoordinate() } /** - * Gets the jar file that we think maven resolved this dependency to (if any). + * Gets the jar file that Maven likely resolved this dependency to (if any). + * See `MavenRepo.getAnArtifact(ProtoPom)` for how this match is determined. */ File getJar() { exists(MavenRepo mr | result = mr.getAnArtifact(this)) } /** - * Gets the scope of this dependency. If the scope tag is present, this will + * Gets the scope of this dependency. If the `scope` tag is present, this will * be the string contents of that tag, otherwise it defaults to "compile". */ string getScope() { @@ -249,14 +252,14 @@ class Dependency extends ProtoPom { } /** - * A Maven dependency element that represents an actual dependency from a given pom project. + * A Maven dependency element that represents an actual dependency from a given POM project. */ class PomDependency extends Dependency { PomDependency() { exists(Pom source | - // This dependency must be a dependency of a pom - dependency tags can also appear in the dependency - // management section, where they do not directly contribute to the dependencies of the containing - // pom. + // This dependency must be a dependency of a POM - dependency tags can also appear in the + // dependencyManagement section, where they do not directly contribute to the dependencies of + // the containing POM. source.getADependency() = this and // Consider dependencies that can be used at compile time. ( @@ -284,7 +287,7 @@ class PomElement extends XMLElement { s = allCharactersString() and if s.matches("${%") then - // Resolve the placeholder in the parent pom + // Resolve the placeholder in the parent POM result = getParent*().(Pom).resolvePlaceholder(s.substring(2, s.length() - 1)) else result = s ) @@ -330,7 +333,7 @@ class Dependencies extends PomElement { Dependency getADependency() { result = this.getAChild() } } -/** An XML element named `dependencyManagement`, as found in Maven POM XML files. */ +/** An XML element named "dependencyManagement", as found in Maven POM XML files. */ class DependencyManagement extends PomElement { DependencyManagement() { getName() = "dependencyManagement" } @@ -340,7 +343,7 @@ class DependencyManagement extends PomElement { /** * Gets a dependency declared in this `dependencyManagement` element that has - * the same (short) coordinates as `dep`. + * the same (short) coordinates as _dep_. */ Dependency getDependency(Dependency dep) { result = getADependency() and @@ -349,7 +352,7 @@ class DependencyManagement extends PomElement { } /** - * An XML element name "properties", as found in Maven POM XML files. + * An XML element named "properties", as found in Maven POM XML files. */ class PomProperties extends PomElement { PomProperties() { this.getName() = "properties" } @@ -366,8 +369,8 @@ class PomProperty extends PomElement { } /** - * A folder that represents a maven local repository using the standard layout. Any folder called - * "repository" with a parent name ".m2" is considered to be a maven repository. + * A folder that represents a local Maven repository using the standard layout. Any folder called + * "repository" with a parent name ".m2" is considered to be a Maven repository. */ class MavenRepo extends Folder { MavenRepo() { getBaseName() = "repository" and getParentContainer().getBaseName() = ".m2" } @@ -378,10 +381,10 @@ class MavenRepo extends Folder { File getAJarFile() { result = getAChildContainer*().(File) and result.getExtension() = "jar" } /** - * Gets any jar artifacts in this repository that match the pom project definition. This is an - * over approximation. For soft qualifiers (e.g. 1.0) we return precise matches in preference to - * artefact only matches. For hard qualifiers (e.g. [1.0]) we return only precise matches. For - * all other qualifiers, we return all matches regardless of version. + * Gets any jar artifacts in this repository that match the POM project definition. This is an + * over approximation. For soft qualifiers (e.g. 1.0) precise matches are returned in preference + * to artifact only matches. For hard qualifiers (e.g. [1.0]) only precise matches are returned. + * For all other qualifiers, all matches are returned regardless of version. */ MavenRepoJar getAnArtifact(ProtoPom pom) { result = getAJarFile() and @@ -389,7 +392,7 @@ class MavenRepo extends Folder { then // Either a hard match qualifier, or soft and there is at least one precise match result.preciseMatch(pom) - else result.artefactMatches(pom) + else result.artifactMatches(pom) } } @@ -401,16 +404,19 @@ private predicate versionHardMatch(ProtoPom pom) { } /** - * A jar file inside a maven repository. + * A jar file inside a Maven repository. * * See: https://cwiki.apache.org/confluence/display/MAVENOLD/Repository+Layout+-+Final */ class MavenRepoJar extends File { MavenRepoJar() { exists(MavenRepo mr | mr.getAJarFile() = this) } - string getGroupID() { + /** + * Gets the `groupId` of this jar. + */ + string getGroupId() { exists(MavenRepo mr | mr.getAJarFile() = this | - // Assuming the standard layout, the first part of the directory structure from the maven + // Assuming the standard layout, the first part of the directory structure from the Maven // repository will be the groupId converted to a path by replacing "." with "/". result = getParentContainer() @@ -422,24 +428,30 @@ class MavenRepoJar extends File { ) } - string getArtefactID() { result = getParentContainer().getParentContainer().getBaseName() } + /** + * Gets the `artifactId` of this jar. + */ + string getArtifactId() { result = getParentContainer().getParentContainer().getBaseName() } + /** + * Gets the artifact version string of this jar. + */ string getVersion() { result = getParentContainer().getBaseName() } /** - * Holds if this jar is an artefact for the given pom or dependency, regardless of which version it is. + * Holds if this jar is an artifact for the given POM or dependency, regardless of which version it is. */ - predicate artefactMatches(ProtoPom pom) { - pom.getGroup().getValue() = getGroupID() and - pom.getArtifact().getValue() = getArtefactID() + predicate artifactMatches(ProtoPom pom) { + pom.getGroup().getValue() = getGroupId() and + pom.getArtifact().getValue() = getArtifactId() } /** - * Holds if this jar is both an artefact for the pom, and has a version string that matches the pom + * Holds if this jar is both an artifact for the POM, and has a version string that matches the POM * version string. Only soft and hard version matches are supported. */ predicate preciseMatch(ProtoPom pom) { - artefactMatches(pom) and + artifactMatches(pom) and if versionHardMatch(pom) then ("[" + getVersion() + "]").matches(pom.getVersionString() + "%") else getVersion().matches(pom.getVersionString() + "%") From e2fbf8a68ca9a301bb166412d9e780d3ecc73c6c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 20:38:05 +0100 Subject: [PATCH 291/429] add files uploaded with `multer` as RemoteFlowSource --- .../semmle/javascript/frameworks/Express.qll | 3 ++- .../CWE-078/CommandInjection.expected | 24 +++++++++++++++++++ .../Security/CWE-078/form-parsers.js | 16 +++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/Express.qll b/javascript/ql/src/semmle/javascript/frameworks/Express.qll index e1519892caf..3931f96cbb6 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Express.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Express.qll @@ -509,8 +509,9 @@ module Express { this = request.getAPropertyRead("cookies") or // `req.files`, treated the same as `req.body`. + // `express-fileupload` uses .files, and `multer` uses .files or .file kind = "body" and - this = request.getAPropertyRead("files") + this = request.getAPropertyRead(["files", "file"]) ) or kind = "body" and diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 5d9c4fcdb61..ec874655c74 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -88,6 +88,18 @@ nodes | execSeries.js:18:34:18:40 | req.url | | execSeries.js:19:12:19:16 | [cmd] | | execSeries.js:19:13:19:15 | cmd | +| form-parsers.js:9:8:9:39 | "touch ... nalname | +| form-parsers.js:9:8:9:39 | "touch ... nalname | +| form-parsers.js:9:19:9:26 | req.file | +| form-parsers.js:9:19:9:26 | req.file | +| form-parsers.js:9:19:9:39 | req.fil ... nalname | +| form-parsers.js:13:3:13:11 | req.files | +| form-parsers.js:13:3:13:11 | req.files | +| form-parsers.js:13:21:13:24 | file | +| form-parsers.js:14:10:14:37 | "touch ... nalname | +| form-parsers.js:14:10:14:37 | "touch ... nalname | +| form-parsers.js:14:21:14:24 | file | +| form-parsers.js:14:21:14:37 | file.originalname | | lib/subLib/index.js:7:32:7:35 | name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -222,6 +234,16 @@ edges | execSeries.js:18:34:18:40 | req.url | execSeries.js:18:13:18:47 | require ... , true) | | execSeries.js:19:12:19:16 | [cmd] | execSeries.js:13:19:13:26 | commands | | execSeries.js:19:13:19:15 | cmd | execSeries.js:19:12:19:16 | [cmd] | +| form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | +| form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:19:9:39 | req.fil ... nalname | +| form-parsers.js:9:19:9:39 | req.fil ... nalname | form-parsers.js:9:8:9:39 | "touch ... nalname | +| form-parsers.js:9:19:9:39 | req.fil ... nalname | form-parsers.js:9:8:9:39 | "touch ... nalname | +| form-parsers.js:13:3:13:11 | req.files | form-parsers.js:13:21:13:24 | file | +| form-parsers.js:13:3:13:11 | req.files | form-parsers.js:13:21:13:24 | file | +| form-parsers.js:13:21:13:24 | file | form-parsers.js:14:21:14:24 | file | +| form-parsers.js:14:21:14:24 | file | form-parsers.js:14:21:14:37 | file.originalname | +| form-parsers.js:14:21:14:37 | file.originalname | form-parsers.js:14:10:14:37 | "touch ... nalname | +| form-parsers.js:14:21:14:37 | file.originalname | form-parsers.js:14:10:14:37 | "touch ... nalname | | lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -293,6 +315,8 @@ edges | exec-sh2.js:10:12:10:57 | cp.spaw ... ptions) | exec-sh2.js:14:25:14:31 | req.url | exec-sh2.js:10:40:10:46 | command | This command depends on $@. | exec-sh2.js:14:25:14:31 | req.url | a user-provided value | | exec-sh.js:15:12:15:61 | cp.spaw ... ptions) | exec-sh.js:19:25:19:31 | req.url | exec-sh.js:15:44:15:50 | command | This command depends on $@. | exec-sh.js:19:25:19:31 | req.url | a user-provided value | | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command depends on $@. | execSeries.js:18:34:18:40 | req.url | a user-provided value | +| form-parsers.js:9:8:9:39 | "touch ... nalname | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | This command depends on $@. | form-parsers.js:9:19:9:26 | req.file | a user-provided value | +| form-parsers.js:14:10:14:37 | "touch ... nalname | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:14:10:14:37 | "touch ... nalname | This command depends on $@. | form-parsers.js:13:3:13:11 | req.files | a user-provided value | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | child_process-test.js:85:37:85:54 | req.query.fileName | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | This command depends on $@. | child_process-test.js:85:37:85:54 | req.query.fileName | a user-provided value | | other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js new file mode 100644 index 00000000000..34054ee7fc3 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js @@ -0,0 +1,16 @@ +var express = require('express'); +var multer = require('multer'); +var upload = multer({ dest: 'uploads/' }); + +var app = express(); +var exec = require("child_process").exec; + +app.post('/profile', upload.single('avatar'), function (req, res, next) { + exec("touch " + req.file.originalname); // NOT OK +}); + +app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) { + req.files.forEach(file => { + exec("touch " + file.originalname); // NOT OK + }) +}); From a03f4ed3cd100e81f5a4c5a7c75a4312ec62dd99 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 8 Feb 2021 21:45:08 +0100 Subject: [PATCH 292/429] add remote flow source for `busboy` --- javascript/ql/src/javascript.qll | 3 +- .../javascript/frameworks/FormParsers.qll | 30 +++++++++++++++++++ .../CWE-078/CommandInjection.expected | 10 +++++++ .../Security/CWE-078/form-parsers.js | 12 ++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index d5c459c4d5c..dcdbcff9a81 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -85,10 +85,11 @@ import semmle.javascript.frameworks.Electron import semmle.javascript.frameworks.EventEmitter import semmle.javascript.frameworks.Files import semmle.javascript.frameworks.Firebase -import semmle.javascript.frameworks.Immutable +import semmle.javascript.frameworks.FormParsers import semmle.javascript.frameworks.jQuery import semmle.javascript.frameworks.JWT import semmle.javascript.frameworks.Handlebars +import semmle.javascript.frameworks.Immutable import semmle.javascript.frameworks.LazyCache import semmle.javascript.frameworks.LodashUnderscore import semmle.javascript.frameworks.Logging diff --git a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll new file mode 100644 index 00000000000..795aaa0802b --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll @@ -0,0 +1,30 @@ +/** + * Provides classes for modelling the server-side form/file parsing libraries. + */ + +import javascript + +/** + * Classes and predicate modelling the `Busboy` library. + */ +module Busboy { + /** + * A `Busboy` instance that has request data flowing into it. + */ + private DataFlow::NewNode busboy() { + result = DataFlow::moduleImport("busboy").getAnInstantiation() and + exists(MethodCallExpr pipe | + pipe.calls(any(HTTP::RequestExpr req), "pipe") and + result.flowsToExpr(pipe.getArgument(0)) + ) + } + + /** + * A source of remote flow from the `Busboy` library. + */ + class BusBoyRemoteFlow extends RemoteFlowSource { + BusBoyRemoteFlow() { this = busboy().getAMemberCall("on").getABoundCallbackParameter(1, _) } + + override string getSourceType() { result = "Busbuy parsed user value" } + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index ec874655c74..d245b61e0fc 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -100,6 +100,11 @@ nodes | form-parsers.js:14:10:14:37 | "touch ... nalname | | form-parsers.js:14:21:14:24 | file | | form-parsers.js:14:21:14:37 | file.originalname | +| form-parsers.js:24:48:24:55 | filename | +| form-parsers.js:24:48:24:55 | filename | +| form-parsers.js:25:10:25:28 | "touch " + filename | +| form-parsers.js:25:10:25:28 | "touch " + filename | +| form-parsers.js:25:21:25:28 | filename | | lib/subLib/index.js:7:32:7:35 | name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -244,6 +249,10 @@ edges | form-parsers.js:14:21:14:24 | file | form-parsers.js:14:21:14:37 | file.originalname | | form-parsers.js:14:21:14:37 | file.originalname | form-parsers.js:14:10:14:37 | "touch ... nalname | | form-parsers.js:14:21:14:37 | file.originalname | form-parsers.js:14:10:14:37 | "touch ... nalname | +| form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:21:25:28 | filename | +| form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:21:25:28 | filename | +| form-parsers.js:25:21:25:28 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | +| form-parsers.js:25:21:25:28 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | | lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -317,6 +326,7 @@ edges | execSeries.js:14:41:14:47 | command | execSeries.js:18:34:18:40 | req.url | execSeries.js:14:41:14:47 | command | This command depends on $@. | execSeries.js:18:34:18:40 | req.url | a user-provided value | | form-parsers.js:9:8:9:39 | "touch ... nalname | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | This command depends on $@. | form-parsers.js:9:19:9:26 | req.file | a user-provided value | | form-parsers.js:14:10:14:37 | "touch ... nalname | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:14:10:14:37 | "touch ... nalname | This command depends on $@. | form-parsers.js:13:3:13:11 | req.files | a user-provided value | +| form-parsers.js:25:10:25:28 | "touch " + filename | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | This command depends on $@. | form-parsers.js:24:48:24:55 | filename | a user-provided value | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | child_process-test.js:85:37:85:54 | req.query.fileName | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | This command depends on $@. | child_process-test.js:85:37:85:54 | req.query.fileName | a user-provided value | | other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js index 34054ee7fc3..02e117f085a 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js @@ -14,3 +14,15 @@ app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) exec("touch " + file.originalname); // NOT OK }) }); + + +var http = require('http'); +var Busboy = require('busboy'); + +http.createServer(function (req, res) { + var busboy = new Busboy({ headers: req.headers }); + busboy.on('file', function (fieldname, file, filename, encoding, mimetype) { + exec("touch " + filename); // NOT OK + }); + req.pipe(busboy); +}).listen(8000); From 61b4ffec3d818cf02d252a794a6df5d95ee81aaa Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 9 Feb 2021 10:16:25 +0100 Subject: [PATCH 293/429] add remote flow from the `Formidable` library --- .../javascript/frameworks/FormParsers.qll | 24 ++++++++++++++++++- .../CWE-078/CommandInjection.expected | 24 +++++++++++++++++++ .../Security/CWE-078/form-parsers.js | 15 ++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll index 795aaa0802b..c43eb57b8b4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll @@ -7,7 +7,7 @@ import javascript /** * Classes and predicate modelling the `Busboy` library. */ -module Busboy { +private module Busboy { /** * A `Busboy` instance that has request data flowing into it. */ @@ -28,3 +28,25 @@ module Busboy { override string getSourceType() { result = "Busbuy parsed user value" } } } + +/** + * A source of remote flow from the `Formidable` library parsing a HTTP request. + */ +private class FormidableRemoteFlow extends RemoteFlowSource { + FormidableRemoteFlow() { + exists(DataFlow::CallNode parse, DataFlow::InvokeNode formidable | + formidable = DataFlow::moduleImport("formidable").getACall() + or + formidable = DataFlow::moduleMember("formidable", "formidable").getACall() + or + formidable = + DataFlow::moduleMember("formidable", ["IncomingForm", "Formidable"]).getAnInstantiation() + | + parse = formidable.getAMemberCall("parse") and + parse.getArgument(0).asExpr() instanceof HTTP::RequestExpr and + this = parse.getABoundCallbackParameter(1, any(int i | i > 0)) + ) + } + + override string getSourceType() { result = "Formidable parsed user value" } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index d245b61e0fc..e0440f1d338 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -105,6 +105,18 @@ nodes | form-parsers.js:25:10:25:28 | "touch " + filename | | form-parsers.js:25:10:25:28 | "touch " + filename | | form-parsers.js:25:21:25:28 | filename | +| form-parsers.js:35:25:35:30 | fields | +| form-parsers.js:35:25:35:30 | fields | +| form-parsers.js:36:10:36:31 | "touch ... ds.name | +| form-parsers.js:36:10:36:31 | "touch ... ds.name | +| form-parsers.js:36:21:36:26 | fields | +| form-parsers.js:36:21:36:31 | fields.name | +| form-parsers.js:40:26:40:31 | fields | +| form-parsers.js:40:26:40:31 | fields | +| form-parsers.js:41:10:41:31 | "touch ... ds.name | +| form-parsers.js:41:10:41:31 | "touch ... ds.name | +| form-parsers.js:41:21:41:26 | fields | +| form-parsers.js:41:21:41:31 | fields.name | | lib/subLib/index.js:7:32:7:35 | name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -253,6 +265,16 @@ edges | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:21:25:28 | filename | | form-parsers.js:25:21:25:28 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | | form-parsers.js:25:21:25:28 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | +| form-parsers.js:35:25:35:30 | fields | form-parsers.js:36:21:36:26 | fields | +| form-parsers.js:35:25:35:30 | fields | form-parsers.js:36:21:36:26 | fields | +| form-parsers.js:36:21:36:26 | fields | form-parsers.js:36:21:36:31 | fields.name | +| form-parsers.js:36:21:36:31 | fields.name | form-parsers.js:36:10:36:31 | "touch ... ds.name | +| form-parsers.js:36:21:36:31 | fields.name | form-parsers.js:36:10:36:31 | "touch ... ds.name | +| form-parsers.js:40:26:40:31 | fields | form-parsers.js:41:21:41:26 | fields | +| form-parsers.js:40:26:40:31 | fields | form-parsers.js:41:21:41:26 | fields | +| form-parsers.js:41:21:41:26 | fields | form-parsers.js:41:21:41:31 | fields.name | +| form-parsers.js:41:21:41:31 | fields.name | form-parsers.js:41:10:41:31 | "touch ... ds.name | +| form-parsers.js:41:21:41:31 | fields.name | form-parsers.js:41:10:41:31 | "touch ... ds.name | | lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -327,6 +349,8 @@ edges | form-parsers.js:9:8:9:39 | "touch ... nalname | form-parsers.js:9:19:9:26 | req.file | form-parsers.js:9:8:9:39 | "touch ... nalname | This command depends on $@. | form-parsers.js:9:19:9:26 | req.file | a user-provided value | | form-parsers.js:14:10:14:37 | "touch ... nalname | form-parsers.js:13:3:13:11 | req.files | form-parsers.js:14:10:14:37 | "touch ... nalname | This command depends on $@. | form-parsers.js:13:3:13:11 | req.files | a user-provided value | | form-parsers.js:25:10:25:28 | "touch " + filename | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | This command depends on $@. | form-parsers.js:24:48:24:55 | filename | a user-provided value | +| form-parsers.js:36:10:36:31 | "touch ... ds.name | form-parsers.js:35:25:35:30 | fields | form-parsers.js:36:10:36:31 | "touch ... ds.name | This command depends on $@. | form-parsers.js:35:25:35:30 | fields | a user-provided value | +| form-parsers.js:41:10:41:31 | "touch ... ds.name | form-parsers.js:40:26:40:31 | fields | form-parsers.js:41:10:41:31 | "touch ... ds.name | This command depends on $@. | form-parsers.js:40:26:40:31 | fields | a user-provided value | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | child_process-test.js:85:37:85:54 | req.query.fileName | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | This command depends on $@. | child_process-test.js:85:37:85:54 | req.query.fileName | a user-provided value | | other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js index 02e117f085a..75c6cf910e3 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js @@ -26,3 +26,18 @@ http.createServer(function (req, res) { }); req.pipe(busboy); }).listen(8000); + + +const formidable = require('formidable'); +app.post('/api/upload', (req, res, next) => { + let form = formidable({ multiples: true }); + + form.parse(req, (err, fields, files) => { + exec("touch " + fields.name); // NOT OK + }); + + let form2 = new formidable.IncomingForm(); + form2.parse(req, (err, fields, files) => { + exec("touch " + fields.name); // NOT OK + }); +}); From 010d580f8e4b44abe579451c5fcd7e20e22e7ed5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 9 Feb 2021 11:00:16 +0100 Subject: [PATCH 294/429] add model for `multiparty` --- .../javascript/frameworks/FormParsers.qll | 37 ++++++++++++++++++- .../CWE-078/CommandInjection.expected | 24 ++++++++++++ .../Security/CWE-078/form-parsers.js | 20 ++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll index c43eb57b8b4..e8f9b76a40e 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll @@ -25,7 +25,7 @@ private module Busboy { class BusBoyRemoteFlow extends RemoteFlowSource { BusBoyRemoteFlow() { this = busboy().getAMemberCall("on").getABoundCallbackParameter(1, _) } - override string getSourceType() { result = "Busbuy parsed user value" } + override string getSourceType() { result = "parsed user value from Busbuy" } } } @@ -48,5 +48,38 @@ private class FormidableRemoteFlow extends RemoteFlowSource { ) } - override string getSourceType() { result = "Formidable parsed user value" } + override string getSourceType() { result = "parsed user value from Formidable" } +} + +/** + * Predicates and classes modelling the `multiparty` library. + */ +private module Multiparty { + /** + * Gets an instance of of `Multiparty` form parser that parses a HTTP request object. + * The `parse` call is the method call that receives the HTTP request object. + */ + private DataFlow::SourceNode form(DataFlow::MethodCallNode parse) { + result = DataFlow::moduleMember("multiparty", "Form").getAnInstantiation() and + parse = result.getAMethodCall("parse") and + parse.getArgument(0).asExpr() instanceof HTTP::RequestExpr + } + + /** + * A source of remote flow from the `Multiparty` library. + */ + class MultipartyRemoteFlow extends RemoteFlowSource { + MultipartyRemoteFlow() { + exists(DataFlow::MethodCallNode parse | exists(form(parse)) | + this = parse.getABoundCallbackParameter(1, any(int i | i > 0)) + ) + or + exists(DataFlow::MethodCallNode on | on = form(_).getAMethodCall("on") | + on.getArgument(0).mayHaveStringValue(["part", "file", "field"]) and + this = on.getABoundCallbackParameter(1, _) + ) + } + + override string getSourceType() { result = "parsed user value from Multiparty" } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index e0440f1d338..3878bbc2088 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -117,6 +117,18 @@ nodes | form-parsers.js:41:10:41:31 | "touch ... ds.name | | form-parsers.js:41:21:41:26 | fields | | form-parsers.js:41:21:41:31 | fields.name | +| form-parsers.js:52:34:52:39 | fields | +| form-parsers.js:52:34:52:39 | fields | +| form-parsers.js:53:10:53:31 | "touch ... ds.name | +| form-parsers.js:53:10:53:31 | "touch ... ds.name | +| form-parsers.js:53:21:53:26 | fields | +| form-parsers.js:53:21:53:31 | fields.name | +| form-parsers.js:58:30:58:33 | part | +| form-parsers.js:58:30:58:33 | part | +| form-parsers.js:59:10:59:33 | "touch ... ilename | +| form-parsers.js:59:10:59:33 | "touch ... ilename | +| form-parsers.js:59:21:59:24 | part | +| form-parsers.js:59:21:59:33 | part.filename | | lib/subLib/index.js:7:32:7:35 | name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -275,6 +287,16 @@ edges | form-parsers.js:41:21:41:26 | fields | form-parsers.js:41:21:41:31 | fields.name | | form-parsers.js:41:21:41:31 | fields.name | form-parsers.js:41:10:41:31 | "touch ... ds.name | | form-parsers.js:41:21:41:31 | fields.name | form-parsers.js:41:10:41:31 | "touch ... ds.name | +| form-parsers.js:52:34:52:39 | fields | form-parsers.js:53:21:53:26 | fields | +| form-parsers.js:52:34:52:39 | fields | form-parsers.js:53:21:53:26 | fields | +| form-parsers.js:53:21:53:26 | fields | form-parsers.js:53:21:53:31 | fields.name | +| form-parsers.js:53:21:53:31 | fields.name | form-parsers.js:53:10:53:31 | "touch ... ds.name | +| form-parsers.js:53:21:53:31 | fields.name | form-parsers.js:53:10:53:31 | "touch ... ds.name | +| form-parsers.js:58:30:58:33 | part | form-parsers.js:59:21:59:24 | part | +| form-parsers.js:58:30:58:33 | part | form-parsers.js:59:21:59:24 | part | +| form-parsers.js:59:21:59:24 | part | form-parsers.js:59:21:59:33 | part.filename | +| form-parsers.js:59:21:59:33 | part.filename | form-parsers.js:59:10:59:33 | "touch ... ilename | +| form-parsers.js:59:21:59:33 | part.filename | form-parsers.js:59:10:59:33 | "touch ... ilename | | lib/subLib/index.js:7:32:7:35 | name | lib/subLib/index.js:8:22:8:25 | name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | | lib/subLib/index.js:8:22:8:25 | name | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | @@ -351,6 +373,8 @@ edges | form-parsers.js:25:10:25:28 | "touch " + filename | form-parsers.js:24:48:24:55 | filename | form-parsers.js:25:10:25:28 | "touch " + filename | This command depends on $@. | form-parsers.js:24:48:24:55 | filename | a user-provided value | | form-parsers.js:36:10:36:31 | "touch ... ds.name | form-parsers.js:35:25:35:30 | fields | form-parsers.js:36:10:36:31 | "touch ... ds.name | This command depends on $@. | form-parsers.js:35:25:35:30 | fields | a user-provided value | | form-parsers.js:41:10:41:31 | "touch ... ds.name | form-parsers.js:40:26:40:31 | fields | form-parsers.js:41:10:41:31 | "touch ... ds.name | This command depends on $@. | form-parsers.js:40:26:40:31 | fields | a user-provided value | +| form-parsers.js:53:10:53:31 | "touch ... ds.name | form-parsers.js:52:34:52:39 | fields | form-parsers.js:53:10:53:31 | "touch ... ds.name | This command depends on $@. | form-parsers.js:52:34:52:39 | fields | a user-provided value | +| form-parsers.js:59:10:59:33 | "touch ... ilename | form-parsers.js:58:30:58:33 | part | form-parsers.js:59:10:59:33 | "touch ... ilename | This command depends on $@. | form-parsers.js:58:30:58:33 | part | a user-provided value | | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | child_process-test.js:85:37:85:54 | req.query.fileName | lib/subLib/index.js:8:10:8:25 | "rm -rf " + name | This command depends on $@. | child_process-test.js:85:37:85:54 | req.query.fileName | a user-provided value | | other.js:7:33:7:35 | cmd | other.js:5:25:5:31 | req.url | other.js:7:33:7:35 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | | other.js:8:28:8:30 | cmd | other.js:5:25:5:31 | req.url | other.js:8:28:8:30 | cmd | This command depends on $@. | other.js:5:25:5:31 | req.url | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js index 75c6cf910e3..4b1dabde441 100644 --- a/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js +++ b/javascript/ql/test/query-tests/Security/CWE-078/form-parsers.js @@ -41,3 +41,23 @@ app.post('/api/upload', (req, res, next) => { exec("touch " + fields.name); // NOT OK }); }); + +var multiparty = require('multiparty'); +var http = require('http'); + +http.createServer(function (req, res) { + // parse a file upload + var form = new multiparty.Form(); + + form.parse(req, function (err, fields, files) { + exec("touch " + fields.name); // NOT OK + }); + + + var form2 = new multiparty.Form(); + form2.on('part', function (part) { // / file / field + exec("touch " + part.filename); // NOT OK + }); + form2.parse(req); + +}).listen(8080); From 044f80215e812797de0f6bce94e229b85f686b68 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 9 Feb 2021 11:20:07 +0100 Subject: [PATCH 295/429] add change note --- javascript/change-notes/2021-02-09-form-parsers.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 javascript/change-notes/2021-02-09-form-parsers.md diff --git a/javascript/change-notes/2021-02-09-form-parsers.md b/javascript/change-notes/2021-02-09-form-parsers.md new file mode 100644 index 00000000000..4ad87cff32b --- /dev/null +++ b/javascript/change-notes/2021-02-09-form-parsers.md @@ -0,0 +1,6 @@ +lgtm,codescanning +* Server side form parsing libraries are now recognized as source of remote user input. + [multer](https://www.npmjs.com/package/multer) and + [busboy](https://www.npmjs.com/package/busboy) and + [formidable](https://www.npmjs.com/package/formidable) and + [multiparty](https://www.npmjs.com/package/formidable) \ No newline at end of file From 3ee0029cd87f4882fd9bf6afefc4c2e3e7bcde28 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 11 Feb 2021 13:33:42 +0100 Subject: [PATCH 296/429] Update javascript/change-notes/2021-02-08-xml-parser-taint.md Co-authored-by: Asger F --- javascript/change-notes/2021-02-08-xml-parser-taint.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/change-notes/2021-02-08-xml-parser-taint.md b/javascript/change-notes/2021-02-08-xml-parser-taint.md index ab59b4f3b92..2028be3e06f 100644 --- a/javascript/change-notes/2021-02-08-xml-parser-taint.md +++ b/javascript/change-notes/2021-02-08-xml-parser-taint.md @@ -1,8 +1,8 @@ lgtm,codescanning * The security queries now track taint through XML parsers. Affected packages are - [xml2js](https://www.npmjs.com/package/xml2js) and - [sax](https://www.npmjs.com/package/sax) and - [xml-js](https://www.npmjs.com/package/xml-js) and - [htmlparser2](https://www.npmjs.com/package/htmlparser2) and + [xml2js](https://www.npmjs.com/package/xml2js), + [sax](https://www.npmjs.com/package/sax), + [xml-js](https://www.npmjs.com/package/xml-js), + [htmlparser2](https://www.npmjs.com/package/htmlparser2), and [node-expat](https://www.npmjs.com/package/node-expat) From f12c38425fe4bde58785b9662b2f6f7800d7bb90 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 10 Feb 2021 18:14:45 +0100 Subject: [PATCH 297/429] add change-note --- javascript/change-notes/2021-02-10-markdown.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 javascript/change-notes/2021-02-10-markdown.md diff --git a/javascript/change-notes/2021-02-10-markdown.md b/javascript/change-notes/2021-02-10-markdown.md new file mode 100644 index 00000000000..3ee12ae65f3 --- /dev/null +++ b/javascript/change-notes/2021-02-10-markdown.md @@ -0,0 +1,8 @@ +lgtm,codescanning +* The dataflow libraries now model dataflow in markdown parses. + Affected packages are + [marked](https://npmjs.com/package/marked), + [markdown-table](https://npmjs.com/package/markdown-table), + [showdown](https://npmjs.com/package/showdown), + [unified](https://npmjs.com/package/unified), and + [remark](https://npmjs.com/package/remark) From d14586de56ed4b82765a3cc5ce21d55161e8e845 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 11 Feb 2021 14:41:45 +0100 Subject: [PATCH 298/429] add two non ReDoS regular expressions to the ReDoS test suite Adds the regular expression from #5145 --- javascript/ql/test/query-tests/Performance/ReDoS/tst.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js index 68549d11e3d..ef45c7f87bd 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/tst.js +++ b/javascript/ql/test/query-tests/Performance/ReDoS/tst.js @@ -351,3 +351,7 @@ var bad79 = /(a*)*b/; var bad80 = /(a+)*b/; var bad81 = /(a*)+b/; var bad82 = /(a+)+b/; + +// GOOD +var good40 = /(a|b)+/; +var good41 = /(?:[\s;,"'<>(){}|[\]@=+*]|:(?![/\\]))+/; From ea30598a08899da1087517e244c3854697107d73 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 11 Feb 2021 16:07:39 +0100 Subject: [PATCH 299/429] Python: Split dotted names more efficiently --- python/ql/src/semmle/python/ApiGraphs.qll | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index 7ad2a795c73..ef29996fd5b 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -319,12 +319,11 @@ module API { * For instance, `prefix_member("foo.bar", "baz", "foo.bar.baz")` would hold. */ private predicate prefix_member(TApiNode base, string member, TApiNode sub) { - exists(string base_str, string sub_str | - base = MkModuleImport(base_str) and + exists(string sub_str, string regexp | + regexp = "(.+)[.]([^.]+)" and + base = MkModuleImport(sub_str.regexpCapture(regexp, 1)) and + member = sub_str.regexpCapture(regexp, 2) and sub = MkModuleImport(sub_str) - | - base_str + "." + member = sub_str and - not member.matches("%.%") ) } From 4c66071f5f976b42b094b179d2b3da4b7ed638e3 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 11 Feb 2021 16:08:28 +0100 Subject: [PATCH 300/429] Python: Revert "Python: Support `moduleImport("dotted.name")` in API graphs" This reverts commit 2c4a477a4e2ba8eda5185feb2268154a7f5932a5. It's probably best _not_ to do this, as any `getMember` cycle in the API graph will lead to nontermination. --- python/ql/src/semmle/python/ApiGraphs.qll | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/python/ql/src/semmle/python/ApiGraphs.qll b/python/ql/src/semmle/python/ApiGraphs.qll index ef29996fd5b..40a3bf4f756 100644 --- a/python/ql/src/semmle/python/ApiGraphs.qll +++ b/python/ql/src/semmle/python/ApiGraphs.qll @@ -209,14 +209,12 @@ module API { /** * Gets a node corresponding to an import of module `m`. + * + * Note: You should only use this predicate for top level modules. If you want nodes corresponding to a submodule, + * you should use `.getMember` on the parent module. For example, for nodes corresponding to the module `foo.bar`, + * use `moduleImport("foo").getMember("bar")`. */ - Node moduleImport(string m) { - result = Impl::MkModuleImport(m) - or - exists(string before_dot, string after_dot | before_dot + "." + after_dot = m | - result = moduleImport(before_dot).getMember(after_dot) - ) - } + Node moduleImport(string m) { result = Impl::MkModuleImport(m) } /** * Provides the actual implementation of API graphs, cached for performance. From 69d8aa143c6532f0e07340698cdb082fcf091e14 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 11 Feb 2021 16:16:46 +0100 Subject: [PATCH 301/429] add taint step for the `snarkdown` libary --- .../change-notes/2021-02-10-markdown.md | 1 + .../semmle/javascript/frameworks/Markdown.qll | 12 ++++++++++ .../ReflectedXss/ReflectedXss.expected | 23 +++++++++++++++++++ .../CWE-079/ReflectedXss/ReflectedXss.js | 9 ++++++++ .../ReflectedXssWithCustomSanitizer.expected | 3 +++ 5 files changed, 48 insertions(+) diff --git a/javascript/change-notes/2021-02-10-markdown.md b/javascript/change-notes/2021-02-10-markdown.md index 3ee12ae65f3..b3c843db0f5 100644 --- a/javascript/change-notes/2021-02-10-markdown.md +++ b/javascript/change-notes/2021-02-10-markdown.md @@ -4,5 +4,6 @@ lgtm,codescanning [marked](https://npmjs.com/package/marked), [markdown-table](https://npmjs.com/package/markdown-table), [showdown](https://npmjs.com/package/showdown), + [snarkdown](https://npmjs.com/package/snarkdown), [unified](https://npmjs.com/package/unified), and [remark](https://npmjs.com/package/remark) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll index 0ea930a3453..bff1c364d00 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Markdown.qll @@ -106,3 +106,15 @@ private module Unified { } } } + +/** + * A taint step for the `snarkdown` library. + */ +private class SnarkdownStep extends TaintTracking::AdditionalTaintStep, DataFlow::CallNode { + SnarkdownStep() { this = DataFlow::moduleImport("snarkdown").getACall() } + + override predicate step(DataFlow::Node pred, DataFlow::Node succ) { + this = succ and + pred = this.getArgument(0) + } +} diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected index cc01ba98932..e0f353a9d32 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.expected @@ -55,6 +55,17 @@ nodes | ReflectedXss.js:74:34:74:34 | f | | ReflectedXss.js:75:14:75:14 | f | | ReflectedXss.js:75:14:75:14 | f | +| ReflectedXss.js:83:12:83:19 | req.body | +| ReflectedXss.js:83:12:83:19 | req.body | +| ReflectedXss.js:83:12:83:19 | req.body | +| ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | +| ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | +| ReflectedXss.js:84:22:84:29 | req.body | +| ReflectedXss.js:84:22:84:29 | req.body | +| ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | +| ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | +| ReflectedXss.js:85:23:85:30 | req.body | +| ReflectedXss.js:85:23:85:30 | req.body | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | @@ -183,6 +194,15 @@ edges | ReflectedXss.js:74:20:74:27 | req.body | ReflectedXss.js:74:34:74:34 | f | | ReflectedXss.js:74:34:74:34 | f | ReflectedXss.js:75:14:75:14 | f | | ReflectedXss.js:74:34:74:34 | f | ReflectedXss.js:75:14:75:14 | f | +| ReflectedXss.js:83:12:83:19 | req.body | ReflectedXss.js:83:12:83:19 | req.body | +| ReflectedXss.js:84:22:84:29 | req.body | ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | +| ReflectedXss.js:84:22:84:29 | req.body | ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | +| ReflectedXss.js:84:22:84:29 | req.body | ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | +| ReflectedXss.js:84:22:84:29 | req.body | ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | +| ReflectedXss.js:85:23:85:30 | req.body | ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | +| ReflectedXss.js:85:23:85:30 | req.body | ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | +| ReflectedXss.js:85:23:85:30 | req.body | ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | +| ReflectedXss.js:85:23:85:30 | req.body | ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | @@ -272,6 +292,9 @@ edges | ReflectedXss.js:68:12:68:52 | remark( ... tring() | ReflectedXss.js:68:33:68:40 | req.body | ReflectedXss.js:68:12:68:52 | remark( ... tring() | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:68:33:68:40 | req.body | user-provided value | | ReflectedXss.js:72:12:72:65 | unified ... oString | ReflectedXss.js:72:48:72:55 | req.body | ReflectedXss.js:72:12:72:65 | unified ... oString | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:72:48:72:55 | req.body | user-provided value | | ReflectedXss.js:75:14:75:14 | f | ReflectedXss.js:74:20:74:27 | req.body | ReflectedXss.js:75:14:75:14 | f | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:74:20:74:27 | req.body | user-provided value | +| ReflectedXss.js:83:12:83:19 | req.body | ReflectedXss.js:83:12:83:19 | req.body | ReflectedXss.js:83:12:83:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:83:12:83:19 | req.body | user-provided value | +| ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | ReflectedXss.js:84:22:84:29 | req.body | ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:84:22:84:29 | req.body | user-provided value | +| ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | ReflectedXss.js:85:23:85:30 | req.body | ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:85:23:85:30 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js index 15f8ea7f7fd..7e531bdd4e1 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXss.js @@ -75,3 +75,12 @@ app.get('/user/:id', function (req, res) { res.send(f); // NOT OK }) }); + +import snarkdown from 'snarkdown'; +var snarkdown2 = require("snarkdown"); + +app.get('/user/:id', function (req, res) { + res.send(req.body); // NOT OK + res.send(snarkdown(req.body)); // NOT OK + res.send(snarkdown2(req.body)); // NOT OK +}); diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected index 96f1093be3b..92017e8f378 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ReflectedXss/ReflectedXssWithCustomSanitizer.expected @@ -11,6 +11,9 @@ | ReflectedXss.js:68:12:68:52 | remark( ... tring() | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:68:33:68:40 | req.body | user-provided value | | ReflectedXss.js:72:12:72:65 | unified ... oString | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:72:48:72:55 | req.body | user-provided value | | ReflectedXss.js:75:14:75:14 | f | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:74:20:74:27 | req.body | user-provided value | +| ReflectedXss.js:83:12:83:19 | req.body | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:83:12:83:19 | req.body | user-provided value | +| ReflectedXss.js:84:12:84:30 | snarkdown(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:84:22:84:29 | req.body | user-provided value | +| ReflectedXss.js:85:12:85:31 | snarkdown2(req.body) | Cross-site scripting vulnerability due to $@. | ReflectedXss.js:85:23:85:30 | req.body | user-provided value | | ReflectedXssContentTypes.js:10:14:10:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:10:24:10:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:20:14:20:36 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:20:24:20:36 | req.params.id | user-provided value | | ReflectedXssContentTypes.js:39:13:39:35 | "FOO: " ... rams.id | Cross-site scripting vulnerability due to $@. | ReflectedXssContentTypes.js:39:23:39:35 | req.params.id | user-provided value | From fd46b7a7bcb1c590a4e113f0daf0c0267d39f994 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 11 Feb 2021 16:17:26 +0100 Subject: [PATCH 302/429] fix type in change-note Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- javascript/change-notes/2021-02-10-markdown.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/change-notes/2021-02-10-markdown.md b/javascript/change-notes/2021-02-10-markdown.md index b3c843db0f5..ed3dfb505e6 100644 --- a/javascript/change-notes/2021-02-10-markdown.md +++ b/javascript/change-notes/2021-02-10-markdown.md @@ -1,5 +1,5 @@ lgtm,codescanning -* The dataflow libraries now model dataflow in markdown parses. +* The dataflow libraries now model dataflow in markdown parsers. Affected packages are [marked](https://npmjs.com/package/marked), [markdown-table](https://npmjs.com/package/markdown-table), From 33b5802ff6fd4b9b5b7cf2173b2c99b515703dda Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 12:42:39 +0000 Subject: [PATCH 303/429] C++: Update StdPair.qll (just for consistency). --- .../semmle/code/cpp/models/implementations/StdPair.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll index 41867e71acc..1d8c4ea44d1 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll @@ -7,8 +7,8 @@ import semmle.code.cpp.models.interfaces.Taint /** * An instantiation of `std::pair`. */ -class StdPairClass extends ClassTemplateInstantiation { - StdPairClass() { getTemplate().hasQualifiedName("std", "pair") } +class StdPair extends ClassTemplateInstantiation { + StdPair() { this.hasQualifiedName("std", "pair") } } /** @@ -18,9 +18,9 @@ class StdPairClass extends ClassTemplateInstantiation { */ class StdPairCopyishConstructor extends Constructor, TaintFunction { StdPairCopyishConstructor() { - this.getDeclaringType() instanceof StdPairClass and + this.getDeclaringType() instanceof StdPair and this.getNumberOfParameters() = 1 and - this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdPairClass + this.getParameter(0).getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdPair } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From 21b2999722c41f481d0265653e4569143b8ddb76 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 13:23:59 +0000 Subject: [PATCH 304/429] C++: Update StdSet.qll. --- .../cpp/models/implementations/StdSet.qll | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll index 9fac9ae75f8..5c30afca572 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll @@ -5,14 +5,18 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Iterator +/** + * An instantiation of `std::set` or `std::unordered_set`. + */ +class StdSet extends ClassTemplateInstantiation { + StdSet() { this.hasQualifiedName("std", ["set", "unordered_set"]) } +} + /** * Additional model for set constructors using iterator inputs. */ private class StdSetConstructor extends Constructor, TaintFunction { - StdSetConstructor() { - this.hasQualifiedName("std", "set", "set") or - this.hasQualifiedName("std", "unordered_set", "unordered_set") - } + StdSetConstructor() { this.getDeclaringType() instanceof StdSet } /** * Gets the index of a parameter to this function that is an iterator. @@ -36,7 +40,7 @@ private class StdSetConstructor extends Constructor, TaintFunction { * The standard set `insert` and `insert_or_assign` functions. */ private class StdSetInsert extends TaintFunction { - StdSetInsert() { this.hasQualifiedName("std", ["set", "unordered_set"], "insert") } + StdSetInsert() { this.getClassAndName("insert") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from last parameter to qualifier and return value @@ -53,9 +57,7 @@ private class StdSetInsert extends TaintFunction { * The standard set `emplace` and `emplace_hint` functions. */ private class StdSetEmplace extends TaintFunction { - StdSetEmplace() { - this.hasQualifiedName("std", ["set", "unordered_set"], ["emplace", "emplace_hint"]) - } + StdSetEmplace() { this.getClassAndName(["emplace", "emplace_hint"]) instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier and return value @@ -76,7 +78,7 @@ private class StdSetEmplace extends TaintFunction { * The standard set `merge` function. */ private class StdSetMerge extends TaintFunction { - StdSetMerge() { this.hasQualifiedName("std", ["set", "unordered_set"], "merge") } + StdSetMerge() { this.getClassAndName("merge") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // container1.merge(container2) @@ -89,7 +91,7 @@ private class StdSetMerge extends TaintFunction { * The standard set `find` function. */ private class StdSetFind extends TaintFunction { - StdSetFind() { this.hasQualifiedName("std", ["set", "unordered_set"], "find") } + StdSetFind() { this.getClassAndName("find") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -101,7 +103,7 @@ private class StdSetFind extends TaintFunction { * The standard set `erase` function. */ private class StdSetErase extends TaintFunction { - StdSetErase() { this.hasQualifiedName("std", ["set", "unordered_set"], "erase") } + StdSetErase() { this.getClassAndName("erase") instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value @@ -116,8 +118,7 @@ private class StdSetErase extends TaintFunction { */ private class StdSetEqualRange extends TaintFunction { StdSetEqualRange() { - this.hasQualifiedName("std", ["set", "unordered_set"], - ["lower_bound", "upper_bound", "equal_range"]) + this.getClassAndName(["lower_bound", "upper_bound", "equal_range"]) instanceof StdSet } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From 91627cbd88ea8606cf2a51ff4233f383423291ef Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 11 Feb 2021 17:21:32 +0100 Subject: [PATCH 305/429] C++: Add models for BSD-style send and recv functions. --- cpp/ql/src/semmle/code/cpp/models/Models.qll | 2 + .../code/cpp/models/implementations/Recv.qll | 73 +++++++++++++++++++ .../code/cpp/models/implementations/Send.qll | 55 ++++++++++++++ .../code/cpp/models/interfaces/FlowSource.qll | 9 +++ .../semmle/code/cpp/security/FlowSources.qll | 28 +++++++ .../src/semmle/code/cpp/security/Security.qll | 15 +++- .../defaulttainttracking.cpp | 19 +++++ .../remote-flow-sink.expected | 0 .../annotate_sinks_only/remote-flow-sink.ql | 20 +++++ 9 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll create mode 100644 cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll create mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.expected create mode 100644 cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 7ec66b3a2e9..c36c1da9bcd 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -28,3 +28,5 @@ private import implementations.Swap private import implementations.GetDelim private import implementations.SmartPointer private import implementations.Sscanf +private import implementations.Send +private import implementations.Recv diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll new file mode 100644 index 00000000000..e7d52472d1d --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll @@ -0,0 +1,73 @@ +/** + * Provides implementation classes modeling `recv` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.ArrayFunction +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.FlowSource +import semmle.code.cpp.models.interfaces.SideEffect + +/** The function `recv` and its assorted variants */ +private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowFunction { + Recv() { + this.hasGlobalName([ + "recv", // recv(socket, dest, len, flags) + "recvfrom", // recvfrom(socket, dest, len, flags, from, fromlen) + "read", // read(socket, dest, len) + "pread" // pread(socket, dest, len, offset) + ]) + } + + override predicate parameterNeverEscapes(int index) { + this.getParameter(index).getUnspecifiedType() instanceof PointerType + } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + bufParam = 1 and countParam = 2 + } + + override predicate hasArrayInput(int bufParam) { this.hasGlobalName("recvfrom") and bufParam = 4 } + + override predicate hasArrayOutput(int bufParam) { + bufParam = 1 + or + this.hasGlobalName("recvfrom") and bufParam = 4 + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + this.hasGlobalName("recvfrom") and + ( + i = 4 and buffer = true + or + i = 5 and buffer = false + ) + } + + override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + i = 1 and buffer = true and mustWrite = false + or + this.hasGlobalName("recvfrom") and + ( + i = 4 and buffer = true and mustWrite = false + or + i = 5 and buffer = false and mustWrite = false + ) + } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasRemoteFlowSource(FunctionOutput output, string description) { + output.isParameterDeref(1) and + description = "Buffer read by " + this.getName() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll new file mode 100644 index 00000000000..414cbd13e7d --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll @@ -0,0 +1,55 @@ +/** + * Provides implementation classes modeling `send` and various similar + * functions. See `semmle.code.cpp.models.Models` for usage information. + */ + +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.ArrayFunction +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.FlowSource +import semmle.code.cpp.models.interfaces.SideEffect + +/** The function `send` and its assorted variants */ +private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowFunctionSink { + Send() { + this.hasGlobalName([ + "send", // send(socket, buf, len, flags) + "sendto", // sendto(socket, buf, len, flags, to, tolen) + "write" // write(socket, buf, len); + ]) + } + + override predicate parameterNeverEscapes(int index) { + this.getParameter(index).getUnspecifiedType() instanceof PointerType + } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasArrayWithVariableSize(int bufParam, int countParam) { + bufParam = 1 and countParam = 2 + } + + override predicate hasArrayInput(int bufParam) { bufParam = 1 } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) { + none() + } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + i = 1 and buffer = true + or + exists(this.getParameter(4)) and i = 4 and buffer = false + } + + override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } + + override predicate hasRemoteFlowSink(FunctionInput input, string description) { + input.isParameterDeref(1) and description = "Buffer sent by " + this.getName() + } +} diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll index c0c95b38756..b3b5d8850ba 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -29,3 +29,12 @@ abstract class LocalFlowFunction extends Function { */ abstract predicate hasLocalFlowSource(FunctionOutput output, string description); } + +/** A library function that sends data over a network connection. */ +abstract class RemoteFlowFunctionSink extends Function { + /** + * Holds if data described by `description` flows into `input` to a call to this function, and is then + * send over a network connection. + */ + abstract predicate hasRemoteFlowSink(FunctionInput input, string description); +} diff --git a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll index c8bad67352b..e3900f1799b 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll @@ -98,3 +98,31 @@ private class ArgvSource extends LocalFlowSource { override string getSourceType() { result = "a command-line argument" } } + +/** A remote data flow sink. */ +abstract class RemoteFlowSink extends DataFlow::Node { + /** Gets a string that describes the type of this flow sink. */ + abstract string getSinkType(); +} + +private class RemoteParameterSink extends RemoteFlowSink { + string sourceType; + + RemoteParameterSink() { + exists(RemoteFlowFunctionSink func, FunctionInput input, CallInstruction call, int index | + func.hasRemoteFlowSink(input, sourceType) and call.getStaticCallTarget() = func + | + exists(ReadSideEffectInstruction read | + call = read.getPrimaryInstruction() and + read.getIndex() = index and + this.asOperand() = read.getSideEffectOperand() and + input.isParameterDerefOrQualifierObject(index) + ) + or + input.isParameterOrQualifierAddress(index) and + this.asOperand() = call.getArgumentOperand(index) + ) + } + + override string getSinkType() { result = sourceType } +} diff --git a/cpp/ql/src/semmle/code/cpp/security/Security.qll b/cpp/ql/src/semmle/code/cpp/security/Security.qll index 16dc89d9a6e..15e9d86ad6a 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Security.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Security.qll @@ -6,6 +6,7 @@ import semmle.code.cpp.exprs.Expr import semmle.code.cpp.commons.Environment import semmle.code.cpp.security.SecurityOptions +import semmle.code.cpp.models.interfaces.FlowSource /** * Extend this class to customize the security queries for @@ -60,7 +61,7 @@ class SecurityOptions extends string { functionCall.getTarget().hasGlobalName(fname) and exists(functionCall.getArgument(arg)) and ( - fname = ["read", "recv", "recvmsg"] and arg = 1 + fname = "recvmsg" and arg = 1 or fname = "getaddrinfo" and arg = 3 or @@ -68,6 +69,12 @@ class SecurityOptions extends string { (arg = 1 or arg = 4 or arg = 5) ) ) + or + exists(RemoteFlowFunction remote, FunctionOutput output | + functionCall.getTarget() = remote and + output.isParameterDerefOrQualifierObject(arg) and + remote.hasRemoteFlowSource(output, _) + ) } /** @@ -81,6 +88,12 @@ class SecurityOptions extends string { userInputReturn(fname) ) ) + or + exists(RemoteFlowFunction remote, FunctionOutput output | + functionCall.getTarget() = remote and + (output.isReturnValue() or output.isReturnValueDeref()) and + remote.hasRemoteFlowSource(output, _) + ) } /** diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp index b24efc1dc8e..6156e80015c 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp @@ -216,3 +216,22 @@ void test_pointers2() sink(ptr4); // clean sink(*ptr4); // $ MISSING: ast,ir } + +// --- recv --- + +int recv(int s, char* buf, int len, int flags); + +void test_recv() { + char buffer[1024]; + recv(0, buffer, sizeof(buffer), 0); + sink(buffer); // $ ast,ir + sink(*buffer); // $ ast,ir +} + +// --- send --- + +int send(int, const void*, int, int); + +void test_send(char* buffer, int length) { + send(0, buffer, length, 0); // $ remote +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.expected b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql new file mode 100644 index 00000000000..4fbbe8fa3bf --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/remote-flow-sink.ql @@ -0,0 +1,20 @@ +/** This tests that we are able to detect remote flow sinks. */ + +import cpp +import TestUtilities.InlineExpectationsTest +import semmle.code.cpp.security.FlowSources + +class RemoteFlowSinkTest extends InlineExpectationsTest { + RemoteFlowSinkTest() { this = "RemoteFlowSinkTest" } + + override string getARelevantTag() { result = "remote" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "remote" and + value = "" and + exists(RemoteFlowSink node | + location = node.getLocation() and + element = node.toString() + ) + } +} From 6f405635ef6fe3ca7343f64c403c4d2a816f4ee6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 11 Feb 2021 17:49:44 +0100 Subject: [PATCH 306/429] add ClientRequest model for apollo-client --- .../javascript/frameworks/ClientRequests.qll | 31 +++++++++++++++++++ .../ClientRequests/ClientRequests.expected | 12 +++++++ .../frameworks/ClientRequests/apollo.js | 23 ++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 javascript/ql/test/library-tests/frameworks/ClientRequests/apollo.js diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index f405b28beca..34f878c125f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -823,4 +823,35 @@ module ClientRequest { override DataFlow::Node getADataNode() { none() } } + + /** + * Classes and predicates modelling the `apollo-client` library. + */ + private module ApolloClient { + /** + * A function from `apollo-client` that accepts an options object that may contain a `uri` property. + */ + API::Node apolloUriCallee() { + result = API::moduleImport("apollo-link-http").getMember(["HttpLink", "createHttpLink"]) + or + result = + API::moduleImport(["apollo-boost", "apollo-client", "apollo-client-preset"]) + .getMember(["ApolloClient", "HttpLink", "createNetworkInterface"]) + or + result = API::moduleImport("apollo-link-ws").getMember("WebSocketLink") + } + + /** + * A model of a URL request made using apollo-client. + */ + class ApolloClientRequeist extends ClientRequest::Range, API::InvokeNode { + ApolloClientRequeist() { this = apolloUriCallee().getAnInvocation() } + + override DataFlow::Node getUrl() { result = getParameter(0).getMember("uri").getARhs() } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } + } } diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected index 5ba426c968f..47c340f7a8e 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected @@ -1,4 +1,10 @@ test_ClientRequest +| apollo.js:5:18:5:78 | new cre ... hql' }) | +| apollo.js:10:1:10:54 | new Htt ... hql' }) | +| apollo.js:14:16:14:69 | new Apo ... .com'}) | +| apollo.js:17:1:17:34 | new Pre ... yurl"}) | +| apollo.js:20:1:20:77 | createN ... phql'}) | +| apollo.js:23:1:23:31 | new Web ... wsUri}) | | tst.js:11:5:11:16 | request(url) | | tst.js:13:5:13:20 | request.get(url) | | tst.js:15:5:15:23 | request.delete(url) | @@ -111,6 +117,12 @@ test_getHost | tst.js:93:5:93:35 | net.req ... host }) | tst.js:93:29:93:32 | host | | tst.js:219:5:219:41 | data.so ... Host"}) | tst.js:219:32:219:39 | "myHost" | test_getUrl +| apollo.js:5:18:5:78 | new cre ... hql' }) | apollo.js:5:44:5:75 | 'https: ... raphql' | +| apollo.js:10:1:10:54 | new Htt ... hql' }) | apollo.js:10:21:10:51 | 'http:/ ... raphql' | +| apollo.js:14:16:14:69 | new Apo ... .com'}) | apollo.js:14:39:14:67 | 'https: ... le.com' | +| apollo.js:17:1:17:34 | new Pre ... yurl"}) | apollo.js:17:26:17:32 | "myurl" | +| apollo.js:20:1:20:77 | createN ... phql'}) | apollo.js:20:30:20:75 | 'https: ... raphql' | +| apollo.js:23:1:23:31 | new Web ... wsUri}) | apollo.js:23:25:23:29 | wsUri | | tst.js:11:5:11:16 | request(url) | tst.js:11:13:11:15 | url | | tst.js:13:5:13:20 | request.get(url) | tst.js:13:17:13:19 | url | | tst.js:15:5:15:23 | request.delete(url) | tst.js:15:20:15:22 | url | diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/apollo.js b/javascript/ql/test/library-tests/frameworks/ClientRequests/apollo.js new file mode 100644 index 00000000000..9aff4e64ab1 --- /dev/null +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/apollo.js @@ -0,0 +1,23 @@ +import { ApolloClient } from 'apollo-client' +import { HttpLink } from 'apollo-link-http' +import { createHttpLink } from 'apollo-link-http' + +const httpLink = new createHttpLink({ uri: 'https://api.github.com/graphql' }) // url 1 + +const ApolloClient = require('apollo-client-preset').ApolloClient; +const HttpLink = require('apollo-link-http').HttpLink; + +new HttpLink({ uri: 'http://localhost:8080/graphql' }); // url 2 + +import ApolloClient from 'apollo-boost'; // / 'apollo-client' + +const client = new ApolloClient({uri: 'https://graphql.example.com'}); // url 3 + +let PresetHttpLink = require('apollo-client-preset').HttpLink; +new PresetHttpLink({uri: "myurl"}); // url 4 + +import { createNetworkInterface } from 'apollo-client'; +createNetworkInterface({uri: 'https://web-go-demo.herokuapp.com/__/graphql'}) // url 5 + +const { WebSocketLink } = require('apollo-link-ws') +new WebSocketLink({uri: wsUri}) // url 6 \ No newline at end of file From 004147a22fda52a7585a3814ba64544f174b9b60 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 11 Feb 2021 17:54:53 +0100 Subject: [PATCH 307/429] add change note --- javascript/change-notes/2021-02-11-apollo-client.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 javascript/change-notes/2021-02-11-apollo-client.md diff --git a/javascript/change-notes/2021-02-11-apollo-client.md b/javascript/change-notes/2021-02-11-apollo-client.md new file mode 100644 index 00000000000..93ec78f1f41 --- /dev/null +++ b/javascript/change-notes/2021-02-11-apollo-client.md @@ -0,0 +1,8 @@ +lgtm,codescanning +* URIs used in the Apollo-link libraries are now recognized as sinks for `js/request-forgery`. + Affected packages are + [apollo-link-http](https://www.npmjs.com/package/apollo-link-http), + [apollo-client](https://www.npmjs.com/package/apollo-client), + [apollo-boost](https://www.npmjs.com/package/apollo-boost), + [apollo-client-preset](https://www.npmjs.com/package/apollo-client-preset), and + [apollo-link-ws](https://www.npmjs.com/package/apollo-link-ws) From 354f21f2c326c08eb663d557af980a3af9d169a8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 14:22:46 +0000 Subject: [PATCH 308/429] C++: BSL support. --- cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll | 2 +- cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll index 1d8c4ea44d1..42c3b9025f8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll @@ -8,7 +8,7 @@ import semmle.code.cpp.models.interfaces.Taint * An instantiation of `std::pair`. */ class StdPair extends ClassTemplateInstantiation { - StdPair() { this.hasQualifiedName("std", "pair") } + StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") } } /** diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll index 5c30afca572..68e78776968 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll @@ -9,7 +9,7 @@ import semmle.code.cpp.models.interfaces.Iterator * An instantiation of `std::set` or `std::unordered_set`. */ class StdSet extends ClassTemplateInstantiation { - StdSet() { this.hasQualifiedName("std", ["set", "unordered_set"]) } + StdSet() { this.hasQualifiedName(["std", "bsl"], ["set", "unordered_set"]) } } /** From 710ca21d19d70b69a38d6dddc75d0150c0485225 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Thu, 11 Feb 2021 11:52:58 -0800 Subject: [PATCH 309/429] Addressing comments we missed earlier --- .../backdoor/ProcessNameToHashTaintFlow.ql | 5 +-- ...mberOfKnownMethodNamesAboveThreshold.qhelp | 2 +- .../NumberOfKnownMethodNamesAboveThreshold.ql | 3 +- .../Cryptography/NonCryptographicHashes.qll | 41 ++++++------------- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql index d6fd090540e..14d0cc02e44 100644 --- a/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql +++ b/csharp/ql/src/experimental/Security Features/backdoor/ProcessNameToHashTaintFlow.ql @@ -36,11 +36,10 @@ predicate isGetHash(Expr arg) { mc.getAnArgument() = arg ) or - exists(Callable callable, Parameter param, Call call, int i | + exists(Callable callable, Parameter param, Call call | isCallableAPotentialNonCryptographicHashFunction(callable, param) and - callable.getParameter(i) = param and call = callable.getACall() and - call.getArgument(i) = arg + arg = call.getArgumentForParameter(param) ) } diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp index 9216fa9e2e5..f75f1e27097 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp @@ -4,7 +4,7 @@

    This query detects method names used in the Solorigate code.

    -

    This query detects when the code includes at least 50 of the mthods used in the Solorigate tampered code

    +

    This query detects when the code includes at least 50 of the methods used in the Solorigate tampered code

    Please notice that by themselves these method names are not malign.

    diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql index c60281882b8..430329c3a10 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.ql @@ -18,8 +18,7 @@ import Solorigate */ int countSolorigateSuspiciousMethodNames() { - result = - count(string s | exists(Method m | s = m.getName() and s = solorigateSuspiciousMethodNames())) + result = count(string s | s = any(Method m | isSolorigateSuspiciousMethodName(m)).getName()) } from Method m, int total, int threshold diff --git a/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll index ea4368af7f6..4e6c40205ec 100644 --- a/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll +++ b/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -23,17 +23,15 @@ predicate maybeANonCryptogrphicHash(Callable callable, Variable v, Expr xor, Exp * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression * followed by a multiplication `mul` expression. */ -predicate maybeUsedInFNVFunction(Variable v, Expr xor, Expr mul, LoopStmt loop) { +predicate maybeUsedInFNVFunction(Variable v, Operation xor, Operation mul, LoopStmt loop) { exists(Expr e1, Expr e2 | - exists(Operation axore, Operation amule | xor = axore and mul = amule | - e1.getAChild*() = v.getAnAccess() and - e2.getAChild*() = v.getAnAccess() and - e1 = axore.getAnOperand() and - e2 = amule.getAnOperand() and - axore.getAControlFlowNode().getASuccessor*() = amule.getAControlFlowNode() and - (axore instanceof AssignXorExpr or axore instanceof BitwiseXorExpr) and - (amule instanceof AssignMulExpr or amule instanceof MulExpr) - ) + e1.getAChild*() = v.getAnAccess() and + e2.getAChild*() = v.getAnAccess() and + e1 = xor.getAnOperand() and + e2 = mul.getAnOperand() and + xor.getAControlFlowNode().getASuccessor*() = mul.getAControlFlowNode() and + (xor instanceof AssignXorExpr or xor instanceof BitwiseXorExpr) and + (mul instanceof AssignMulExpr or mul instanceof MulExpr) ) and loop.getAChild*() = mul.getEnclosingStmt() and loop.getAChild*() = xor.getEnclosingStmt() @@ -44,13 +42,11 @@ predicate maybeUsedInFNVFunction(Variable v, Expr xor, Expr mul, LoopStmt loop) * where there is a loop statement `loop` where the variable `v` is used in an xor `xor` expression * followed by an addition `add` expression. */ -predicate maybeUsedInElfHashFunction(Variable v, Expr xorExpr, Expr addExpr, LoopStmt loop) { +private predicate maybeUsedInElfHashFunction(Variable v, Operation xor, Operation add, LoopStmt loop) { exists( - Expr e1, Operation add, Expr e2, AssignExpr addAssign, Operation xor, AssignExpr xorAssign, - Operation notOp, AssignExpr notAssign + Expr e1, Expr e2, AssignExpr addAssign, AssignExpr xorAssign, Operation notOp, + AssignExpr notAssign | - xorExpr = xor and - addExpr = add and (add instanceof AddExpr or add instanceof AssignAddExpr) and e1.getAChild*() = add.getAnOperand() and e1 instanceof BinaryBitwiseOperation and @@ -70,17 +66,6 @@ predicate maybeUsedInElfHashFunction(Variable v, Expr xorExpr, Expr addExpr, Loo ) } -/** - * Any dataflow from any source to any sink, used internally - */ -private class AnyDataFlow extends TaintTracking2::Configuration { - AnyDataFlow() { this = "DataFlowFromDataGatheringMethodToVariable" } - - override predicate isSource(Node source) { any() } - - override predicate isSink(Node sink) { any() } -} - /** * Holds if the Callable is a function that behaves like a non-cryptographic hash * where the parameter `param` is likely the message to hash @@ -94,13 +79,13 @@ predicate isCallableAPotentialNonCryptographicHashFunction(Callable callable, Pa or param.getAnAccess() = op2.(Operation).getAnOperand().getAChild*() or - exists(AnyDataFlow config, Node source, Node sink | + exists(Node source, Node sink | ( sink.asExpr() = op1.(Operation).getAChild*() or sink.asExpr() = op2.(Operation).getAChild*() ) and source.asExpr() = param.getAnAccess() and - config.hasFlow(source, sink) + DataFlow::localFlow(source, sink) ) ) ) From e89891fa1fa01a1e1711a7daef3ef8fe45bf2781 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Fri, 12 Feb 2021 01:30:47 +0100 Subject: [PATCH 310/429] Address review comments --- java/ql/src/semmle/code/xml/MavenPom.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/xml/MavenPom.qll b/java/ql/src/semmle/code/xml/MavenPom.qll index 30c1e673b23..bbbb4580340 100644 --- a/java/ql/src/semmle/code/xml/MavenPom.qll +++ b/java/ql/src/semmle/code/xml/MavenPom.qll @@ -167,7 +167,7 @@ class Pom extends ProtoPom { Pom getParentPom() { result = getParentElement().getPom() } /** - * Gets the version specified for dependency _dep_ in a `dependencyManagement` + * Gets the version specified for dependency `dep` in a `dependencyManagement` * section in this POM or one of its ancestors, or an empty string if no version * is specified. */ @@ -343,7 +343,7 @@ class DependencyManagement extends PomElement { /** * Gets a dependency declared in this `dependencyManagement` element that has - * the same (short) coordinates as _dep_. + * the same (short) coordinates as `dep`. */ Dependency getDependency(Dependency dep) { result = getADependency() and @@ -383,7 +383,7 @@ class MavenRepo extends Folder { /** * Gets any jar artifacts in this repository that match the POM project definition. This is an * over approximation. For soft qualifiers (e.g. 1.0) precise matches are returned in preference - * to artifact only matches. For hard qualifiers (e.g. [1.0]) only precise matches are returned. + * to artifact-only matches. For hard qualifiers (e.g. [1.0]) only precise matches are returned. * For all other qualifiers, all matches are returned regardless of version. */ MavenRepoJar getAnArtifact(ProtoPom pom) { From 0aded1549eff5acd3c2d476c5eee6453e1517885 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 12 Feb 2021 09:33:33 +0100 Subject: [PATCH 311/429] Improve NestedLoopsSameVariable query performance --- csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql b/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql index 3e71e7c7894..f0eb93926c0 100644 --- a/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql +++ b/csharp/ql/src/Likely Bugs/NestedLoopsSameVariable.ql @@ -28,7 +28,8 @@ class NestedForConditions extends SC::StructuralComparisonConfiguration { } private predicate hasChild(Stmt outer, Element child) { - outer = child.getParent() + outer = child.getParent() and + (outer instanceof ForStmt or outer = any(ForStmt f).getBody()) or hasChild(outer, child.getParent()) } From ed2dc5f6ad7c85a635306f10393a36f0c0ad6fe7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 12 Feb 2021 10:26:31 +0100 Subject: [PATCH 312/429] Python: Fix date for change-note --- ...1-django-improvements.md => 2021-02-10-django-improvements.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/change-notes/{2021-12-21-django-improvements.md => 2021-02-10-django-improvements.md} (100%) diff --git a/python/change-notes/2021-12-21-django-improvements.md b/python/change-notes/2021-02-10-django-improvements.md similarity index 100% rename from python/change-notes/2021-12-21-django-improvements.md rename to python/change-notes/2021-02-10-django-improvements.md From b1c7cb63968e391c8da7d64a932d4282196ac50b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 12 Feb 2021 10:31:27 +0100 Subject: [PATCH 313/429] C++: Address review comments. --- .../CWE/CWE-020/ExternalAPIsSpecific.qll | 2 +- .../code/cpp/models/implementations/Fread.qll | 2 +- .../cpp/models/implementations/GetDelim.qll | 2 +- .../code/cpp/models/implementations/Getenv.qll | 2 +- .../code/cpp/models/implementations/Gets.qll | 2 +- .../code/cpp/models/implementations/Recv.qll | 18 +++++++++++++++--- .../code/cpp/models/implementations/Send.qll | 11 ++++++++--- .../code/cpp/models/interfaces/FlowSource.qll | 12 ++++++------ .../semmle/code/cpp/security/FlowSources.qll | 10 +++++----- .../src/semmle/code/cpp/security/Security.qll | 14 ++++---------- 10 files changed, 43 insertions(+), 32 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll index 788baeddbff..9ca598f86d6 100644 --- a/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll +++ b/cpp/ql/src/Security/CWE/CWE-020/ExternalAPIsSpecific.qll @@ -46,7 +46,7 @@ class UntrustedDataToExternalAPIConfig extends TaintTracking::Configuration { UntrustedDataToExternalAPIConfig() { this = "UntrustedDataToExternalAPIConfig" } override predicate isSource(DataFlow::Node source) { - exists(RemoteFlowFunction remoteFlow | + exists(RemoteFlowSourceFunction remoteFlow | remoteFlow = source.asExpr().(Call).getTarget() and remoteFlow.hasRemoteFlowSource(_, _) ) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll index 11568c8a974..9524b18b0a2 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll @@ -1,7 +1,7 @@ import semmle.code.cpp.models.interfaces.Alias import semmle.code.cpp.models.interfaces.FlowSource -private class Fread extends AliasFunction, RemoteFlowFunction { +private class Fread extends AliasFunction, RemoteFlowSourceFunction { Fread() { this.hasGlobalName("fread") } override predicate parameterNeverEscapes(int n) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll index 3561caee7fb..e2015406346 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/GetDelim.qll @@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.FlowSource * The standard functions `getdelim`, `getwdelim` and the glibc variant `__getdelim`. */ private class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectFunction, - RemoteFlowFunction { + RemoteFlowSourceFunction { GetDelimFunction() { hasGlobalName(["getdelim", "getwdelim", "__getdelim"]) } override predicate hasTaintFlow(FunctionInput i, FunctionOutput o) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll index 9761a4293a8..93b601de752 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll @@ -8,7 +8,7 @@ import semmle.code.cpp.models.interfaces.FlowSource /** * The POSIX function `getenv`. */ -class Getenv extends LocalFlowFunction { +class Getenv extends LocalFlowSourceFunction { Getenv() { this.hasGlobalName("getenv") } override predicate hasLocalFlowSource(FunctionOutput output, string description) { diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index 91653cd6b37..f698a1209f4 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -14,7 +14,7 @@ import semmle.code.cpp.models.interfaces.FlowSource * The standard functions `gets` and `fgets`. */ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunction, AliasFunction, - SideEffectFunction, RemoteFlowFunction { + SideEffectFunction, RemoteFlowSourceFunction { GetsFunction() { // gets(str) // fgets(str, num, stream) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll index e7d52472d1d..ef919c9eb39 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll @@ -10,11 +10,13 @@ import semmle.code.cpp.models.interfaces.FlowSource import semmle.code.cpp.models.interfaces.SideEffect /** The function `recv` and its assorted variants */ -private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowFunction { +private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, + RemoteFlowSourceFunction { Recv() { this.hasGlobalName([ "recv", // recv(socket, dest, len, flags) "recvfrom", // recvfrom(socket, dest, len, flags, from, fromlen) + "recvmsg", // recvmsg(socket, msg, flags) "read", // read(socket, dest, len) "pread" // pread(socket, dest, len, offset) ]) @@ -29,7 +31,9 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, Rem override predicate parameterIsAlwaysReturned(int index) { none() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - bufParam = 1 and countParam = 2 + not this.hasGlobalName("recvmsg") and + bufParam = 1 and + countParam = 2 } override predicate hasArrayInput(int bufParam) { this.hasGlobalName("recvfrom") and bufParam = 4 } @@ -47,6 +51,10 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, Rem or i = 5 and buffer = false ) + or + this.hasGlobalName("recvmsg") and + i = 1 and + buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } @@ -67,7 +75,11 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, Rem override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasRemoteFlowSource(FunctionOutput output, string description) { - output.isParameterDeref(1) and + ( + output.isParameterDeref(1) + or + this.hasGlobalName("recvfrom") and output.isParameterDeref([4, 5]) + ) and description = "Buffer read by " + this.getName() } } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll index 414cbd13e7d..2a6cd0bac51 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll @@ -10,11 +10,12 @@ import semmle.code.cpp.models.interfaces.FlowSource import semmle.code.cpp.models.interfaces.SideEffect /** The function `send` and its assorted variants */ -private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowFunctionSink { +private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, RemoteFlowSinkFunction { Send() { this.hasGlobalName([ "send", // send(socket, buf, len, flags) "sendto", // sendto(socket, buf, len, flags, to, tolen) + "sendmsg", // sendmsg(socket, msg, flags) "write" // write(socket, buf, len); ]) } @@ -28,7 +29,9 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem override predicate parameterIsAlwaysReturned(int index) { none() } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - bufParam = 1 and countParam = 2 + not this.hasGlobalName("sendmsg") and + bufParam = 1 and + countParam = 2 } override predicate hasArrayInput(int bufParam) { bufParam = 1 } @@ -44,7 +47,9 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { i = 1 and buffer = true or - exists(this.getParameter(4)) and i = 4 and buffer = false + this.hasGlobalName("sendto") and i = 4 and buffer = false + or + this.hasGlobalName("sendmsg") and i = 1 and buffer = true } override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 } diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll index b3b5d8850ba..8f953761cdc 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -1,9 +1,9 @@ /** - * Provides a class for modeling functions that return data from potentially untrusted sources. To use - * this QL library, create a QL class extending `DataFlowFunction` with a + * Provides classes for modeling functions that return data from (or send data to) potentially untrusted + * sources. To use this QL library, create a QL class extending `DataFlowFunction` with a * characteristic predicate that selects the function or set of functions you * are modeling. Within that class, override the predicates provided by - * `RemoteFlowFunction` to match the flow within that function. + * `RemoteFlowSourceFunction` or `RemoteFlowSinkFunction` to match the flow within that function. */ import cpp @@ -13,7 +13,7 @@ import semmle.code.cpp.models.Models /** * A library function that returns data that may be read from a network connection. */ -abstract class RemoteFlowFunction extends Function { +abstract class RemoteFlowSourceFunction extends Function { /** * Holds if remote data described by `description` flows from `output` of a call to this function. */ @@ -23,7 +23,7 @@ abstract class RemoteFlowFunction extends Function { /** * A library function that returns data that is directly controlled by a user. */ -abstract class LocalFlowFunction extends Function { +abstract class LocalFlowSourceFunction extends Function { /** * Holds if data described by `description` flows from `output` of a call to this function. */ @@ -31,7 +31,7 @@ abstract class LocalFlowFunction extends Function { } /** A library function that sends data over a network connection. */ -abstract class RemoteFlowFunctionSink extends Function { +abstract class RemoteFlowSinkFunction extends Function { /** * Holds if data described by `description` flows into `input` to a call to this function, and is then * send over a network connection. diff --git a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll index e3900f1799b..b080651951f 100644 --- a/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll +++ b/cpp/ql/src/semmle/code/cpp/security/FlowSources.qll @@ -23,7 +23,7 @@ private class RemoteReturnSource extends RemoteFlowSource { string sourceType; RemoteReturnSource() { - exists(RemoteFlowFunction func, CallInstruction instr, FunctionOutput output | + exists(RemoteFlowSourceFunction func, CallInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getStaticCallTarget() = func and func.hasRemoteFlowSource(output, sourceType) and @@ -42,7 +42,7 @@ private class RemoteParameterSource extends RemoteFlowSource { string sourceType; RemoteParameterSource() { - exists(RemoteFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | + exists(RemoteFlowSourceFunction func, WriteSideEffectInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and func.hasRemoteFlowSource(output, sourceType) and @@ -57,7 +57,7 @@ private class LocalReturnSource extends LocalFlowSource { string sourceType; LocalReturnSource() { - exists(LocalFlowFunction func, CallInstruction instr, FunctionOutput output | + exists(LocalFlowSourceFunction func, CallInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getStaticCallTarget() = func and func.hasLocalFlowSource(output, sourceType) and @@ -76,7 +76,7 @@ private class LocalParameterSource extends LocalFlowSource { string sourceType; LocalParameterSource() { - exists(LocalFlowFunction func, WriteSideEffectInstruction instr, FunctionOutput output | + exists(LocalFlowSourceFunction func, WriteSideEffectInstruction instr, FunctionOutput output | asInstruction() = instr and instr.getPrimaryInstruction().(CallInstruction).getStaticCallTarget() = func and func.hasLocalFlowSource(output, sourceType) and @@ -109,7 +109,7 @@ private class RemoteParameterSink extends RemoteFlowSink { string sourceType; RemoteParameterSink() { - exists(RemoteFlowFunctionSink func, FunctionInput input, CallInstruction call, int index | + exists(RemoteFlowSinkFunction func, FunctionInput input, CallInstruction call, int index | func.hasRemoteFlowSink(input, sourceType) and call.getStaticCallTarget() = func | exists(ReadSideEffectInstruction read | diff --git a/cpp/ql/src/semmle/code/cpp/security/Security.qll b/cpp/ql/src/semmle/code/cpp/security/Security.qll index 15e9d86ad6a..d39c13a25a0 100644 --- a/cpp/ql/src/semmle/code/cpp/security/Security.qll +++ b/cpp/ql/src/semmle/code/cpp/security/Security.qll @@ -60,17 +60,11 @@ class SecurityOptions extends string { or functionCall.getTarget().hasGlobalName(fname) and exists(functionCall.getArgument(arg)) and - ( - fname = "recvmsg" and arg = 1 - or - fname = "getaddrinfo" and arg = 3 - or - fname = "recvfrom" and - (arg = 1 or arg = 4 or arg = 5) - ) + fname = "getaddrinfo" and + arg = 3 ) or - exists(RemoteFlowFunction remote, FunctionOutput output | + exists(RemoteFlowSourceFunction remote, FunctionOutput output | functionCall.getTarget() = remote and output.isParameterDerefOrQualifierObject(arg) and remote.hasRemoteFlowSource(output, _) @@ -89,7 +83,7 @@ class SecurityOptions extends string { ) ) or - exists(RemoteFlowFunction remote, FunctionOutput output | + exists(RemoteFlowSourceFunction remote, FunctionOutput output | functionCall.getTarget() = remote and (output.isReturnValue() or output.isReturnValueDeref()) and remote.hasRemoteFlowSource(output, _) From 729c7f23719f494638c1fb011211cd3b67359e88 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 12 Feb 2021 10:53:34 +0100 Subject: [PATCH 314/429] C++: Add deprecated alias to RemoteFlowSourceFunction and LocalFlowSourceFunction. --- .../code/cpp/models/interfaces/FlowSource.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll index 8f953761cdc..8c80377c8ec 100644 --- a/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll +++ b/cpp/ql/src/semmle/code/cpp/models/interfaces/FlowSource.qll @@ -20,6 +20,13 @@ abstract class RemoteFlowSourceFunction extends Function { abstract predicate hasRemoteFlowSource(FunctionOutput output, string description); } +/** + * DEPRECATED: Use `RemoteFlowSourceFunction` instead. + * + * A library function that returns data that may be read from a network connection. + */ +deprecated class RemoteFlowFunction = RemoteFlowSourceFunction; + /** * A library function that returns data that is directly controlled by a user. */ @@ -30,6 +37,13 @@ abstract class LocalFlowSourceFunction extends Function { abstract predicate hasLocalFlowSource(FunctionOutput output, string description); } +/** + * DEPRECATED: Use `LocalFlowSourceFunction` instead. + * + * A library function that returns data that is directly controlled by a user. + */ +deprecated class LocalFlowFunction = LocalFlowSourceFunction; + /** A library function that sends data over a network connection. */ abstract class RemoteFlowSinkFunction extends Function { /** From 1651f81ac8f2d9592321841ce978f5a95826aad7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 12 Feb 2021 12:19:12 +0100 Subject: [PATCH 315/429] Python: Refactor to avoid confusing name After discussion with @yoff --- python/ql/src/semmle/python/frameworks/Django.qll | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index fee806ff8ef..6e90d5adee0 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2024,8 +2024,15 @@ private module Django { result = djangoRouteHandlerFunctionTracker(DataFlow::TypeTracker::end(), func) } - /** A class that might be a django View class. */ - class PossibleDjangoViewClass extends Class { + /** + * In order to recognize a class as being a django view class, based on the `as_view` + * call, we need to be able to track such calls on _any_ class. This is provided by + * the member predicates of this QL class. + * + * As such, a Python class being part of `DjangoViewClassHelper` doesn't signify that + * we model it as a django view class. + */ + class DjangoViewClassHelper extends Class { /** Gets a reference to this class. */ private DataFlow::Node getARef(DataFlow::TypeTracker t) { t.start() and @@ -2061,7 +2068,7 @@ private module Django { } /** A class that we consider a django View class. */ - abstract class DjangoViewClass extends PossibleDjangoViewClass { + abstract class DjangoViewClass extends DjangoViewClassHelper { /** Gets a function that could handle incoming requests, if any. */ Function getARequestHandler() { // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with From 97df60f9d6284f9f8d3823d71c0f5fb32e6c2ecf Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 12 Feb 2021 12:12:16 +0000 Subject: [PATCH 316/429] Move misplaced experimental query into the conventional directory --- .../experimental/{ => Security/CWE}/CWE-918/RequestForgery.java | 0 .../{ => Security/CWE}/CWE-918/RequestForgery.qhelp | 0 .../experimental/{ => Security/CWE}/CWE-918/RequestForgery.ql | 0 .../experimental/{ => Security/CWE}/CWE-918/RequestForgery.qll | 0 .../query-tests/security/CWE-918/RequestForgery.qlref | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) rename java/ql/src/experimental/{ => Security/CWE}/CWE-918/RequestForgery.java (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-918/RequestForgery.qhelp (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-918/RequestForgery.ql (100%) rename java/ql/src/experimental/{ => Security/CWE}/CWE-918/RequestForgery.qll (100%) diff --git a/java/ql/src/experimental/CWE-918/RequestForgery.java b/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.java similarity index 100% rename from java/ql/src/experimental/CWE-918/RequestForgery.java rename to java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.java diff --git a/java/ql/src/experimental/CWE-918/RequestForgery.qhelp b/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qhelp similarity index 100% rename from java/ql/src/experimental/CWE-918/RequestForgery.qhelp rename to java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qhelp diff --git a/java/ql/src/experimental/CWE-918/RequestForgery.ql b/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.ql similarity index 100% rename from java/ql/src/experimental/CWE-918/RequestForgery.ql rename to java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.ql diff --git a/java/ql/src/experimental/CWE-918/RequestForgery.qll b/java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qll similarity index 100% rename from java/ql/src/experimental/CWE-918/RequestForgery.qll rename to java/ql/src/experimental/Security/CWE/CWE-918/RequestForgery.qll diff --git a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref b/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref index 3d529ae5a2c..3e35024c212 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref +++ b/java/ql/test/experimental/query-tests/security/CWE-918/RequestForgery.qlref @@ -1 +1 @@ -experimental/CWE-918/RequestForgery.ql \ No newline at end of file +experimental/Security/CWE/CWE-918/RequestForgery.ql From 655cfb3a475432e5cb019207a065481102dfb93e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 12 Feb 2021 12:24:19 +0000 Subject: [PATCH 317/429] Re-introduce deprecated versions of old Maven predicate names --- java/ql/src/semmle/code/xml/MavenPom.qll | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/java/ql/src/semmle/code/xml/MavenPom.qll b/java/ql/src/semmle/code/xml/MavenPom.qll index bbbb4580340..f13680b2b44 100644 --- a/java/ql/src/semmle/code/xml/MavenPom.qll +++ b/java/ql/src/semmle/code/xml/MavenPom.qll @@ -428,11 +428,21 @@ class MavenRepoJar extends File { ) } + /** + * DEPRECATED: name changed to `getGroupId` for consistent use of camel-case. + */ + deprecated string getGroupID() { result = getGroupId() } + /** * Gets the `artifactId` of this jar. */ string getArtifactId() { result = getParentContainer().getParentContainer().getBaseName() } + /** + * DEPRECATED: name changed to `getArtifactId` for consistent casing and consistent spelling with Maven. + */ + deprecated string getArtefactID() { result = getArtifactId() } + /** * Gets the artifact version string of this jar. */ @@ -446,6 +456,11 @@ class MavenRepoJar extends File { pom.getArtifact().getValue() = getArtifactId() } + /** + * DEPRECATED: name changed to `artifactMatches` for consistent spelling with Maven. + */ + deprecated predicate artefactMatches(ProtoPom pom) { artifactMatches(pom) } + /** * Holds if this jar is both an artifact for the POM, and has a version string that matches the POM * version string. Only soft and hard version matches are supported. From 49eda8ced626299e28d5257634369e7c9cc40570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Fri, 12 Feb 2021 14:56:10 +0100 Subject: [PATCH 318/429] apply LSP formatter --- .../code/java/frameworks/apache/Lang.qll | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index e31b2e30861..c9af49464e0 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -3,17 +3,18 @@ import java private import semmle.code.java.dataflow.FlowSteps -/** - * The class `org.apache.commons.lang.RandomStringUtils` or `org.apache.commons.lang3.RandomStringUtils`. +/** + * The class `org.apache.commons.lang.RandomStringUtils` or `org.apache.commons.lang3.RandomStringUtils`. */ class TypeApacheRandomStringUtils extends Class { TypeApacheRandomStringUtils() { - this.hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "RandomStringUtils") + this.hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], + "RandomStringUtils") } } -/** - * The class `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils`. +/** + * The class `org.apache.commons.lang.ArrayUtils` or `org.apache.commons.lang3.ArrayUtils`. */ class TypeApacheArrayUtils extends Class { TypeApacheArrayUtils() { @@ -27,7 +28,9 @@ class TypeApacheArrayUtils extends Class { */ class MethodApacheSerializationUtilsDeserialize extends Method { MethodApacheSerializationUtilsDeserialize() { - this.getDeclaringType().hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], "SerializationUtils") and + this.getDeclaringType() + .hasQualifiedName(["org.apache.commons.lang", "org.apache.commons.lang3"], + "SerializationUtils") and this.hasName("deserialize") } } @@ -44,12 +47,16 @@ private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingC this.hasName(["addAll", "addFirst"]) and src = [0 .. getNumberOfParameters()] or - this.hasName(["clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse", "shift", "shuffle", "subarray", "swap", "toArray", "toMap", "toObject", "toPrimitive", "toString", "toStringArray"]) and + this.hasName([ + "clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse", + "shift", "shuffle", "subarray", "swap", "toArray", "toMap", "toObject", "toPrimitive", + "toString", "toStringArray" + ]) and src = 0 or this.hasName("add") and this.getNumberOfParameters() = 2 and - src = [0,1,2] + src = [0, 1, 2] or this.hasName("add") and this.getNumberOfParameters() = 3 and From 8606386c2ce297221e08ff9cf81c261225a0d1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Fri, 12 Feb 2021 14:59:28 +0100 Subject: [PATCH 319/429] add bidirectional import --- java/ql/src/semmle/code/java/dataflow/FlowSteps.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll index d129ee6544e..cb219650414 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll @@ -16,6 +16,7 @@ module Frameworks { private import semmle.code.java.frameworks.Guice private import semmle.code.java.frameworks.Protobuf private import semmle.code.java.frameworks.guava.Guava + private import semmle.code.java.frameworks.apache.Lang } /** From 6b80a429139cd6748b87312b30543c0efacb7804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Fri, 12 Feb 2021 15:03:11 +0100 Subject: [PATCH 320/429] apply LSP formatter and add missing dot --- java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll b/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll index 04b3be0a3dc..db5687f916a 100644 --- a/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll +++ b/java/ql/src/semmle/code/java/frameworks/SnakeYaml.qll @@ -17,12 +17,10 @@ class SnakeYamlSafeConstructor extends RefType { } /** - * An instance of `SafeConstructor` + * An instance of `SafeConstructor`. */ class SafeSnakeYamlConstruction extends ClassInstanceExpr { - SafeSnakeYamlConstruction() { - this.getConstructedType() instanceof SnakeYamlSafeConstructor - } + SafeSnakeYamlConstruction() { this.getConstructedType() instanceof SnakeYamlSafeConstructor } } /** From 7d294361dc2e762948a59344a64e753a7e02d7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 12 Feb 2021 15:40:44 +0100 Subject: [PATCH 321/429] Update java/ql/src/semmle/code/java/frameworks/apache/Lang.qll Co-authored-by: Joe Farebrother --- java/ql/src/semmle/code/java/frameworks/apache/Lang.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index c9af49464e0..6f0d8739382 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -56,7 +56,7 @@ private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingC or this.hasName("add") and this.getNumberOfParameters() = 2 and - src = [0, 1, 2] + src = [0, 1] or this.hasName("add") and this.getNumberOfParameters() = 3 and From 7705fc4f98af10ddac36af39dc9be75019d4ede1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 Feb 2021 11:28:07 +0000 Subject: [PATCH 322/429] C++: Add more test cases for iterator taint flow. --- .../dataflow/taint-tests/localTaint.expected | 107 ++++++++++++++++++ .../taint-tests/standalone_iterators.cpp | 31 +++++ .../dataflow/taint-tests/vector.cpp | 36 ++++++ 3 files changed, 174 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 9f038101d67..50cfca5c990 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3197,6 +3197,52 @@ | standalone_iterators.cpp:90:8:90:8 | call to operator-- | standalone_iterators.cpp:90:5:90:5 | call to operator* | TAINT | | standalone_iterators.cpp:90:8:90:8 | ref arg call to operator-- | standalone_iterators.cpp:90:6:90:7 | ref arg i2 | | | standalone_iterators.cpp:90:13:90:13 | 0 | standalone_iterators.cpp:90:5:90:5 | ref arg call to operator* | TAINT | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:101:6:101:7 | c1 | | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:102:6:102:7 | c1 | | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:98:15:98:16 | call to container | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:101:6:101:7 | c1 | standalone_iterators.cpp:101:9:101:13 | call to begin | TAINT | +| standalone_iterators.cpp:101:6:101:7 | ref arg c1 | standalone_iterators.cpp:102:6:102:7 | c1 | | +| standalone_iterators.cpp:101:6:101:7 | ref arg c1 | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:101:6:101:7 | ref arg c1 | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:101:9:101:13 | call to begin | standalone_iterators.cpp:101:2:101:15 | ... = ... | | +| standalone_iterators.cpp:101:9:101:13 | call to begin | standalone_iterators.cpp:103:3:103:3 | a | | +| standalone_iterators.cpp:101:9:101:13 | call to begin | standalone_iterators.cpp:104:7:104:7 | a | | +| standalone_iterators.cpp:102:6:102:7 | c1 | standalone_iterators.cpp:102:9:102:13 | call to begin | TAINT | +| standalone_iterators.cpp:102:6:102:7 | ref arg c1 | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:102:6:102:7 | ref arg c1 | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:102:9:102:13 | call to begin | standalone_iterators.cpp:102:2:102:15 | ... = ... | | +| standalone_iterators.cpp:102:9:102:13 | call to begin | standalone_iterators.cpp:107:7:107:7 | b | | +| standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | standalone_iterators.cpp:103:3:103:3 | ref arg a | TAINT | +| standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:103:3:103:3 | a | standalone_iterators.cpp:103:2:103:2 | call to operator* | TAINT | +| standalone_iterators.cpp:103:3:103:3 | ref arg a | standalone_iterators.cpp:104:7:104:7 | a | | +| standalone_iterators.cpp:103:7:103:12 | call to source | standalone_iterators.cpp:103:2:103:2 | ref arg call to operator* | TAINT | +| standalone_iterators.cpp:104:7:104:7 | a [post update] | standalone_iterators.cpp:106:6:106:7 | c1 | | +| standalone_iterators.cpp:104:7:104:7 | a [post update] | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:106:6:106:7 | c1 | standalone_iterators.cpp:106:9:106:13 | call to begin | TAINT | +| standalone_iterators.cpp:106:6:106:7 | ref arg c1 | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:106:9:106:13 | call to begin | standalone_iterators.cpp:106:2:106:15 | ... = ... | | +| standalone_iterators.cpp:106:9:106:13 | call to begin | standalone_iterators.cpp:108:7:108:7 | c | | +| standalone_iterators.cpp:107:7:107:7 | b [post update] | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:108:7:108:7 | c [post update] | standalone_iterators.cpp:109:7:109:8 | c1 | | +| standalone_iterators.cpp:113:15:113:16 | call to container | standalone_iterators.cpp:116:7:116:8 | c1 | | +| standalone_iterators.cpp:113:15:113:16 | call to container | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:116:7:116:8 | c1 | standalone_iterators.cpp:116:10:116:14 | call to begin | TAINT | +| standalone_iterators.cpp:116:7:116:8 | ref arg c1 | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:116:2:116:16 | ... = ... | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:117:7:117:8 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:118:2:118:3 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:119:7:119:8 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:120:2:120:3 | it | | +| standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:121:7:121:8 | it | | +| standalone_iterators.cpp:117:7:117:8 | it [post update] | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:119:7:119:8 | it | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:120:2:120:3 | it | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | | +| standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | | | stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT | | stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT | | stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | | @@ -7481,3 +7527,64 @@ | vector.cpp:496:25:496:30 | call to source | vector.cpp:496:2:496:3 | ref arg v2 | TAINT | | vector.cpp:496:25:496:30 | call to source | vector.cpp:496:5:496:11 | call to emplace | TAINT | | vector.cpp:497:7:497:8 | ref arg v2 | vector.cpp:498:1:498:1 | v2 | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:506:8:506:9 | as | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:507:8:507:9 | as | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:509:9:509:10 | as | | +| vector.cpp:503:18:503:21 | {...} | vector.cpp:515:8:515:9 | as | | +| vector.cpp:503:20:503:20 | 0 | vector.cpp:503:18:503:21 | {...} | TAINT | +| vector.cpp:506:8:506:9 | as | vector.cpp:506:8:506:12 | access to array | | +| vector.cpp:506:11:506:11 | 1 | vector.cpp:506:8:506:12 | access to array | TAINT | +| vector.cpp:507:8:507:9 | as | vector.cpp:507:8:507:19 | access to array | | +| vector.cpp:507:11:507:16 | call to source | vector.cpp:507:8:507:19 | access to array | TAINT | +| vector.cpp:509:9:509:10 | as | vector.cpp:509:3:509:10 | ... = ... | | +| vector.cpp:509:9:509:10 | as | vector.cpp:510:9:510:11 | ptr | | +| vector.cpp:509:9:509:10 | as | vector.cpp:511:3:511:5 | ptr | | +| vector.cpp:510:9:510:11 | ptr | vector.cpp:510:8:510:11 | * ... | TAINT | +| vector.cpp:511:3:511:5 | ptr | vector.cpp:511:3:511:10 | ... += ... | TAINT | +| vector.cpp:511:3:511:10 | ... += ... | vector.cpp:512:9:512:11 | ptr | | +| vector.cpp:511:3:511:10 | ... += ... | vector.cpp:513:3:513:5 | ptr | | +| vector.cpp:511:10:511:10 | 1 | vector.cpp:511:3:511:10 | ... += ... | TAINT | +| vector.cpp:512:9:512:11 | ptr | vector.cpp:512:8:512:11 | * ... | TAINT | +| vector.cpp:513:3:513:5 | ptr | vector.cpp:513:3:513:17 | ... += ... | TAINT | +| vector.cpp:513:3:513:17 | ... += ... | vector.cpp:514:9:514:11 | ptr | | +| vector.cpp:513:10:513:15 | call to source | vector.cpp:513:3:513:17 | ... += ... | TAINT | +| vector.cpp:514:9:514:11 | ptr | vector.cpp:514:8:514:11 | * ... | TAINT | +| vector.cpp:515:8:515:9 | as | vector.cpp:515:8:515:12 | access to array | | +| vector.cpp:515:11:515:11 | 1 | vector.cpp:515:8:515:12 | access to array | TAINT | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:523:8:523:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:524:8:524:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:526:8:526:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:520:25:520:31 | call to vector | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:520:30:520:30 | 0 | vector.cpp:520:25:520:31 | call to vector | TAINT | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:524:8:524:9 | vs | | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:523:8:523:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:523:8:523:9 | vs | vector.cpp:523:10:523:10 | call to operator[] | TAINT | +| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:526:8:526:9 | vs | | +| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:524:8:524:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:524:8:524:9 | vs | vector.cpp:524:10:524:10 | call to operator[] | TAINT | +| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:532:8:532:9 | vs | | +| vector.cpp:526:8:526:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:526:8:526:9 | vs | vector.cpp:526:11:526:15 | call to begin | TAINT | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:526:3:526:17 | ... = ... | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:527:9:527:10 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:528:3:528:4 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:529:9:529:10 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:530:3:530:4 | it | | +| vector.cpp:526:11:526:15 | call to begin | vector.cpp:531:9:531:10 | it | | +| vector.cpp:527:9:527:10 | it | vector.cpp:527:8:527:8 | call to operator* | TAINT | +| vector.cpp:528:3:528:4 | it | vector.cpp:528:6:528:6 | call to operator+= | | +| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:529:9:529:10 | it | | +| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:530:3:530:4 | it | | +| vector.cpp:528:3:528:4 | ref arg it | vector.cpp:531:9:531:10 | it | | +| vector.cpp:528:9:528:9 | 1 | vector.cpp:528:6:528:6 | call to operator+= | | +| vector.cpp:529:9:529:10 | it | vector.cpp:529:8:529:8 | call to operator* | TAINT | +| vector.cpp:530:3:530:4 | it | vector.cpp:530:6:530:6 | call to operator+= | | +| vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | | +| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:6:530:6 | call to operator+= | | +| vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT | +| vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | +| vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp index 3fb8c738305..0d6760f08a9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp @@ -90,3 +90,34 @@ void test_insert_iterator() { *i2-- = 0; sink(c2); // clean } + +void sink(insert_iterator_by_trait); +insert_iterator_by_trait &operator+=(insert_iterator_by_trait &it, int amount); + +void test_assign_through_iterator() { + container c1; + insert_iterator_by_trait a, b, c; + + a = c1.begin(); + b = c1.begin(); + *a = source(); + sink(a); // $ ast MISSING: ir + + c = c1.begin(); + sink(b); // MISSING: ast,ir + sink(c); // $ ast MISSING: ir + sink(c1); // $ ast MISSING: ir +} + +void test_nonmember_iterator() { + container c1; + insert_iterator_by_trait it; + + it = c1.begin(); + sink(it); + it += 1; + sink(it); + it += source(); + sink(it); // $ MISSING: ast,ir + sink(c1); +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp index ec354da548c..5d040988dd8 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -496,3 +496,39 @@ void test_vector_emplace() { v2.emplace(v2.begin(), source()); sink(v2); // $ ast,ir } + +void test_vector_iterator() { + { + // array behaviour, for comparison + short as[100] = {0}; + short *ptr; + + sink(as[1]); + sink(as[source()]); // $ ast,ir + + ptr = as; + sink(*ptr); + ptr += 1; + sink(*ptr); + ptr += source(); + sink(*ptr); // $ ast,ir + sink(as[1]); + } + + { + // iterator behaviour + std::vector vs(100, 0); + std::vector::iterator it; + + sink(vs[1]); + sink(vs[source()]); // $ MISSING: ast,ir + + it = vs.begin(); + sink(*it); + it += 1; + sink(*it); + it += source(); + sink(*it); // $ MISSING: ast,ir + sink(vs[1]); + } +} From 90dbbbb0c22991eb87fb5306f9b2bb655c646bbb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 14:53:09 +0000 Subject: [PATCH 323/429] C++: Update Iterator.qll. --- .../cpp/models/implementations/Iterator.qll | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index a5b1c0e83ec..16d1e273707 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -177,8 +177,7 @@ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunctio class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunction, IteratorReferenceFunction { IteratorPointerDereferenceMemberOperator() { - this.hasName("operator*") and - this.getDeclaringType() instanceof Iterator + this.getClassAndName("operator*") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -195,8 +194,7 @@ class IteratorPointerDereferenceMemberOperator extends MemberFunction, TaintFunc */ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction { IteratorCrementMemberOperator() { - this.hasName(["operator++", "operator--"]) and - this.getDeclaringType() instanceof Iterator + this.getClassAndName(["operator++", "operator--"]) instanceof Iterator } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -221,8 +219,7 @@ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunc */ private class IteratorFieldMemberOperator extends Operator, TaintFunction { IteratorFieldMemberOperator() { - this.hasName("operator->") and - this.getDeclaringType() instanceof Iterator + this.getClassAndName("operator->") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -236,8 +233,7 @@ private class IteratorFieldMemberOperator extends Operator, TaintFunction { */ private class IteratorBinaryArithmeticMemberOperator extends MemberFunction, TaintFunction { IteratorBinaryArithmeticMemberOperator() { - this.hasName(["operator+", "operator-"]) and - this.getDeclaringType() instanceof Iterator + this.getClassAndName(["operator+", "operator-"]) instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -252,8 +248,7 @@ private class IteratorBinaryArithmeticMemberOperator extends MemberFunction, Tai private class IteratorAssignArithmeticMemberOperator extends MemberFunction, DataFlowFunction, TaintFunction { IteratorAssignArithmeticMemberOperator() { - this.hasName(["operator+=", "operator-="]) and - this.getDeclaringType() instanceof Iterator + this.getClassAndName(["operator+=", "operator-="]) instanceof Iterator } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -276,8 +271,7 @@ private class IteratorAssignArithmeticMemberOperator extends MemberFunction, Dat private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction, IteratorReferenceFunction { IteratorArrayMemberOperator() { - this.hasName("operator[]") and - this.getDeclaringType() instanceof Iterator + this.getClassAndName("operator[]") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -295,8 +289,7 @@ private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction, */ private class IteratorAssignmentMemberOperator extends MemberFunction, TaintFunction { IteratorAssignmentMemberOperator() { - this.hasName("operator=") and - this.getDeclaringType() instanceof Iterator and + this.getClassAndName("operator=") instanceof Iterator and not this instanceof CopyAssignmentOperator and not this instanceof MoveAssignmentOperator } From da06b2a615804b43b2edba1b14877006c0fd9fcf Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 16:44:05 +0000 Subject: [PATCH 324/429] C++: Improve Iterator.qll layout and QLDoc. --- .../code/cpp/models/implementations/Iterator.qll | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index 16d1e273707..5aeefb760ae 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -26,6 +26,14 @@ private class IteratorTraits extends Class { Type getIteratorType() { result = this.getTemplateArgument(0) } } +/** + * A type that is deduced to be an iterator because there is a corresponding + * `std::iterator_traits` instantiation for it. + */ +private class IteratorByTraits extends Iterator { + IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) } +} + /** * A type which has the typedefs expected for an iterator. */ @@ -48,13 +56,9 @@ private class StdIterator extends Iterator, Class { } /** - * A type that is deduced to be an iterator because there is a corresponding - * `std::iterator_traits` instantiation for it. + * Gets the `FunctionInput` corresponding to an iterator parameter to + * user-defined operator `op`, at `index`. */ -private class IteratorByTraits extends Iterator { - IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) } -} - private FunctionInput getIteratorArgumentInput(Operator op, int index) { exists(Type t | t = From 61b0d6a0cd0a18db306c3a43a29e1b87d3329926 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 16:27:37 +0000 Subject: [PATCH 325/429] C++: Fix Iterator.qll non-member operator+= charpred. --- .../semmle/code/cpp/models/implementations/Iterator.qll | 4 +++- .../dataflow/taint-tests/localTaint.expected | 8 ++++---- .../dataflow/taint-tests/standalone_iterators.cpp | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index 5aeefb760ae..b21055d60e8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -157,9 +157,11 @@ private class IteratorSubOperator extends Operator, TaintFunction { * A non-member `operator+=` or `operator-=` function for an iterator type. */ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction { + FunctionInput iteratorInput; + IteratorAssignArithmeticOperator() { this.hasName(["operator+=", "operator-="]) and - this.getDeclaringType() instanceof Iterator + iteratorInput = getIteratorArgumentInput(this, 0) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { 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 50cfca5c990..5c002dc6455 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3238,11 +3238,15 @@ | standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:120:2:120:3 | it | | | standalone_iterators.cpp:116:10:116:14 | call to begin | standalone_iterators.cpp:121:7:121:8 | it | | | standalone_iterators.cpp:117:7:117:8 | it [post update] | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:118:2:118:3 | it | standalone_iterators.cpp:118:5:118:5 | call to operator+= | | | standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:119:7:119:8 | it | | | standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:120:2:120:3 | it | | | standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | | | standalone_iterators.cpp:118:2:118:3 | ref arg it | standalone_iterators.cpp:122:7:122:8 | c1 | | +| standalone_iterators.cpp:118:8:118:8 | 1 | standalone_iterators.cpp:118:2:118:3 | ref arg it | TAINT | +| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | | | standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | | +| standalone_iterators.cpp:120:8:120:13 | call to source | standalone_iterators.cpp:120:2:120:3 | ref arg it | TAINT | | stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT | | stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT | | stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | | @@ -3922,12 +3926,10 @@ | string.cpp:408:8:408:9 | i2 | string.cpp:409:10:409:11 | i7 | | | string.cpp:409:10:409:11 | i7 | string.cpp:409:12:409:12 | call to operator+= | | | string.cpp:409:12:409:12 | call to operator+= | string.cpp:409:8:409:8 | call to operator* | TAINT | -| string.cpp:409:14:409:14 | 1 | string.cpp:409:12:409:12 | call to operator+= | | | string.cpp:410:8:410:9 | i2 | string.cpp:410:3:410:9 | ... = ... | | | string.cpp:410:8:410:9 | i2 | string.cpp:411:10:411:11 | i8 | | | string.cpp:411:10:411:11 | i8 | string.cpp:411:12:411:12 | call to operator-= | | | string.cpp:411:12:411:12 | call to operator-= | string.cpp:411:8:411:8 | call to operator* | TAINT | -| string.cpp:411:14:411:14 | 1 | string.cpp:411:12:411:12 | call to operator-= | | | string.cpp:413:8:413:9 | s2 | string.cpp:413:11:413:13 | call to end | TAINT | | string.cpp:413:11:413:13 | call to end | string.cpp:413:3:413:15 | ... = ... | | | string.cpp:413:11:413:13 | call to end | string.cpp:414:5:414:6 | i9 | | @@ -7580,11 +7582,9 @@ | vector.cpp:528:3:528:4 | ref arg it | vector.cpp:529:9:529:10 | it | | | vector.cpp:528:3:528:4 | ref arg it | vector.cpp:530:3:530:4 | it | | | vector.cpp:528:3:528:4 | ref arg it | vector.cpp:531:9:531:10 | it | | -| vector.cpp:528:9:528:9 | 1 | vector.cpp:528:6:528:6 | call to operator+= | | | vector.cpp:529:9:529:10 | it | vector.cpp:529:8:529:8 | call to operator* | TAINT | | vector.cpp:530:3:530:4 | it | vector.cpp:530:6:530:6 | call to operator+= | | | vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | | -| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:6:530:6 | call to operator+= | | | vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT | | vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | | vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp index 0d6760f08a9..362784eeb1a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/standalone_iterators.cpp @@ -118,6 +118,6 @@ void test_nonmember_iterator() { it += 1; sink(it); it += source(); - sink(it); // $ MISSING: ast,ir + sink(it); // $ ast,ir sink(c1); } From 3cfb0a21fef0bb60b32708f15ec4b57b0a0739de Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 11 Feb 2021 16:28:42 +0000 Subject: [PATCH 326/429] C++: Fix Iterator.qll taint/data flows for operator+=. --- .../cpp/models/implementations/Iterator.qll | 26 +++++++++++-------- .../dataflow/taint-tests/localTaint.expected | 4 +++ .../dataflow/taint-tests/vector.cpp | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index b21055d60e8..c15f127d1de 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -167,11 +167,15 @@ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunctio override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameter(0) and output.isReturnValue() - or - input.isParameterDeref(0) and output.isReturnValueDeref() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isParameterDeref(0) and output.isReturnValueDeref() + or + // reverse flow from returned reference to the object referenced by the first parameter + input.isReturnValueDeref() and + output.isParameterDeref(0) + or input.isParameterDeref(1) and output.isParameterDeref(0) } @@ -224,9 +228,7 @@ private class IteratorCrementMemberOperator extends MemberFunction, DataFlowFunc * A member `operator->` function for an iterator type. */ private class IteratorFieldMemberOperator extends Operator, TaintFunction { - IteratorFieldMemberOperator() { - this.getClassAndName("operator->") instanceof Iterator - } + IteratorFieldMemberOperator() { this.getClassAndName("operator->") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -260,14 +262,18 @@ private class IteratorAssignArithmeticMemberOperator extends MemberFunction, Dat override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isQualifierAddress() and output.isReturnValue() - or - input.isReturnValueDeref() and - output.isQualifierObject() } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier + input.isReturnValueDeref() and + output.isQualifierObject() + or + input.isParameterDeref(0) and + output.isQualifierObject() } } @@ -276,9 +282,7 @@ private class IteratorAssignArithmeticMemberOperator extends MemberFunction, Dat */ private class IteratorArrayMemberOperator extends MemberFunction, TaintFunction, IteratorReferenceFunction { - IteratorArrayMemberOperator() { - this.getClassAndName("operator[]") instanceof Iterator - } + IteratorArrayMemberOperator() { this.getClassAndName("operator[]") instanceof Iterator } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and 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 5c002dc6455..eb8d93e1b9a 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -3926,10 +3926,12 @@ | string.cpp:408:8:408:9 | i2 | string.cpp:409:10:409:11 | i7 | | | string.cpp:409:10:409:11 | i7 | string.cpp:409:12:409:12 | call to operator+= | | | string.cpp:409:12:409:12 | call to operator+= | string.cpp:409:8:409:8 | call to operator* | TAINT | +| string.cpp:409:14:409:14 | 1 | string.cpp:409:10:409:11 | ref arg i7 | TAINT | | string.cpp:410:8:410:9 | i2 | string.cpp:410:3:410:9 | ... = ... | | | string.cpp:410:8:410:9 | i2 | string.cpp:411:10:411:11 | i8 | | | string.cpp:411:10:411:11 | i8 | string.cpp:411:12:411:12 | call to operator-= | | | string.cpp:411:12:411:12 | call to operator-= | string.cpp:411:8:411:8 | call to operator* | TAINT | +| string.cpp:411:14:411:14 | 1 | string.cpp:411:10:411:11 | ref arg i8 | TAINT | | string.cpp:413:8:413:9 | s2 | string.cpp:413:11:413:13 | call to end | TAINT | | string.cpp:413:11:413:13 | call to end | string.cpp:413:3:413:15 | ... = ... | | | string.cpp:413:11:413:13 | call to end | string.cpp:414:5:414:6 | i9 | | @@ -7582,9 +7584,11 @@ | vector.cpp:528:3:528:4 | ref arg it | vector.cpp:529:9:529:10 | it | | | vector.cpp:528:3:528:4 | ref arg it | vector.cpp:530:3:530:4 | it | | | vector.cpp:528:3:528:4 | ref arg it | vector.cpp:531:9:531:10 | it | | +| vector.cpp:528:9:528:9 | 1 | vector.cpp:528:3:528:4 | ref arg it | TAINT | | vector.cpp:529:9:529:10 | it | vector.cpp:529:8:529:8 | call to operator* | TAINT | | vector.cpp:530:3:530:4 | it | vector.cpp:530:6:530:6 | call to operator+= | | | vector.cpp:530:3:530:4 | ref arg it | vector.cpp:531:9:531:10 | it | | +| vector.cpp:530:9:530:14 | call to source | vector.cpp:530:3:530:4 | ref arg it | TAINT | | vector.cpp:531:9:531:10 | it | vector.cpp:531:8:531:8 | call to operator* | TAINT | | vector.cpp:532:8:532:9 | ref arg vs | vector.cpp:533:2:533:2 | vs | | | vector.cpp:532:8:532:9 | vs | vector.cpp:532:10:532:10 | call to operator[] | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp index 5d040988dd8..4f0c8fab414 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -528,7 +528,7 @@ void test_vector_iterator() { it += 1; sink(*it); it += source(); - sink(*it); // $ MISSING: ast,ir + sink(*it); // $ ast,ir sink(vs[1]); } } From 1edfd04598396dd5804801b862c343c589d5c5f9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 Feb 2021 15:56:47 +0000 Subject: [PATCH 327/429] C++: BSL Support. --- .../semmle/code/cpp/models/implementations/Iterator.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index c15f127d1de..e8ad3d454d8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.Iterator */ private class IteratorTraits extends Class { IteratorTraits() { - this.hasQualifiedName("std", "iterator_traits") and + this.hasQualifiedName(["std", "bsl"], "iterator_traits") and not this instanceof TemplateClass and exists(TypedefType t | this.getAMember() = t and @@ -44,7 +44,7 @@ private class IteratorByTypedefs extends Iterator, Class { this.getAMember().(TypedefType).hasName("pointer") and this.getAMember().(TypedefType).hasName("reference") and this.getAMember().(TypedefType).hasName("iterator_category") and - not this.hasQualifiedName("std", "iterator_traits") + not this.hasQualifiedName(["std", "bsl"], "iterator_traits") } } @@ -52,7 +52,7 @@ private class IteratorByTypedefs extends Iterator, Class { * The `std::iterator` class. */ private class StdIterator extends Iterator, Class { - StdIterator() { this.hasQualifiedName("std", "iterator") } + StdIterator() { this.hasQualifiedName(["std", "bsl"], "iterator") } } /** @@ -340,7 +340,7 @@ private class BeginOrEndFunction extends MemberFunction, TaintFunction, GetItera */ private class InserterIteratorFunction extends GetIteratorFunction { InserterIteratorFunction() { - this.hasQualifiedName("std", ["front_inserter", "inserter", "back_inserter"]) + this.hasQualifiedName(["std", "bsl"], ["front_inserter", "inserter", "back_inserter"]) } override predicate getsIterator(FunctionInput input, FunctionOutput output) { From df91b8182cc5d30e07aa766b94f9c8410bfca676 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 Feb 2021 16:24:45 +0000 Subject: [PATCH 328/429] C++: Deprecate StdPairClass properly. --- .../semmle/code/cpp/models/implementations/StdPair.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll index 42c3b9025f8..9076220cc22 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll @@ -7,10 +7,16 @@ import semmle.code.cpp.models.interfaces.Taint /** * An instantiation of `std::pair`. */ -class StdPair extends ClassTemplateInstantiation { +private class StdPair extends ClassTemplateInstantiation { StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") } } +/** + * DEPRECATED: This is now called `StdPair` and is a private part of the + * library implementation. + */ +deprecated class StdPairClass = StdPair; + /** * Any of the single-parameter constructors of `std::pair` that takes a reference to an * instantiation of `std::pair`. These constructors allow conversion between pair types when the From d362b5aa654a4656fcd2974fc842f0b2c8ebbd01 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 Feb 2021 16:29:44 +0000 Subject: [PATCH 329/429] C++: StdSet should be private as well. --- cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll index 68e78776968..d2e9892abcb 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdSet.qll @@ -8,7 +8,7 @@ import semmle.code.cpp.models.interfaces.Iterator /** * An instantiation of `std::set` or `std::unordered_set`. */ -class StdSet extends ClassTemplateInstantiation { +private class StdSet extends ClassTemplateInstantiation { StdSet() { this.hasQualifiedName(["std", "bsl"], ["set", "unordered_set"]) } } From 74f05d569b7d6a8566781d6a7fbcfd26a4bb9fc9 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 Feb 2021 17:41:32 +0000 Subject: [PATCH 330/429] C++: BSL support. --- .../cpp/models/implementations/StdString.qll | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 9f4c458815f..2ffd5916172 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -12,7 +12,7 @@ import semmle.code.cpp.models.interfaces.DataFlow * The `std::basic_string` template class instantiations. */ private class StdBasicString extends ClassTemplateInstantiation { - StdBasicString() { this.hasQualifiedName("std", "basic_string") } + StdBasicString() { this.hasQualifiedName(["std", "bsl"], "basic_string") } } /** @@ -127,7 +127,7 @@ private class StdStringFrontBack extends TaintFunction { */ private class StdStringPlus extends TaintFunction { StdStringPlus() { - this.hasQualifiedName("std", "operator+") and + this.hasQualifiedName(["std", "bsl"], "operator+") and this.getUnspecifiedType() instanceof StdBasicString } @@ -256,7 +256,7 @@ private class StdStringSubstr extends TaintFunction { * The `std::basic_stringstream` template class instantiations. */ private class StdBasicStringStream extends ClassTemplateInstantiation { - StdBasicStringStream() { this.hasQualifiedName("std", "basic_stringstream") } + StdBasicStringStream() { this.hasQualifiedName(["std", "bsl"], "basic_stringstream") } } /** @@ -280,7 +280,7 @@ private class StdStringAt extends TaintFunction { * The `std::basic_istream` template class instantiations. */ private class StdBasicIStream extends ClassTemplateInstantiation { - StdBasicIStream() { this.hasQualifiedName("std", "basic_istream") } + StdBasicIStream() { this.hasQualifiedName(["std", "bsl"], "basic_istream") } } /** @@ -314,7 +314,7 @@ private class StdIStreamIn extends DataFlowFunction, TaintFunction { */ private class StdIStreamInNonMember extends DataFlowFunction, TaintFunction { StdIStreamInNonMember() { - this.hasQualifiedName("std", "operator>>") and + this.hasQualifiedName(["std", "bsl"], "operator>>") and this.getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdBasicIStream } @@ -462,7 +462,7 @@ private class StdIStreamGetLine extends DataFlowFunction, TaintFunction { * The (non-member) function `std::getline`. */ private class StdGetLine extends DataFlowFunction, TaintFunction { - StdGetLine() { this.hasQualifiedName("std", "getline") } + StdGetLine() { this.hasQualifiedName(["std", "bsl"], "getline") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { // flow from first parameter to return value @@ -488,7 +488,7 @@ private class StdGetLine extends DataFlowFunction, TaintFunction { * The `std::basic_ostream` template class instantiations. */ private class StdBasicOStream extends ClassTemplateInstantiation { - StdBasicOStream() { this.hasQualifiedName("std", "basic_ostream") } + StdBasicOStream() { this.hasQualifiedName(["std", "bsl"], "basic_ostream") } } /** @@ -535,7 +535,7 @@ private class StdOStreamOut extends DataFlowFunction, TaintFunction { */ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { StdOStreamOutNonMember() { - this.hasQualifiedName("std", "operator<<") and + this.hasQualifiedName(["std", "bsl"], "operator<<") and this.getUnspecifiedType().(ReferenceType).getBaseType() instanceof StdBasicOStream } @@ -609,7 +609,7 @@ private class StdStringStreamStr extends TaintFunction { * The `std::basic_ios` template class instantiations. */ private class StdBasicIOS extends ClassTemplateInstantiation { - StdBasicIOS() { this.hasQualifiedName("std", "basic_ios") } + StdBasicIOS() { this.hasQualifiedName(["std", "bsl"], "basic_ios") } } /** From 6d452521f75646a507f0f6509c61e6500e1a1581 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 12 Feb 2021 17:42:33 +0000 Subject: [PATCH 331/429] C++: Move StdBasicStringStream to a more logical location. --- .../code/cpp/models/implementations/StdString.qll | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll index 2ffd5916172..73a0f6edf26 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -252,13 +252,6 @@ private class StdStringSubstr extends TaintFunction { } } -/** - * The `std::basic_stringstream` template class instantiations. - */ -private class StdBasicStringStream extends ClassTemplateInstantiation { - StdBasicStringStream() { this.hasQualifiedName(["std", "bsl"], "basic_stringstream") } -} - /** * The `std::string` functions `at` and `operator[]`. */ @@ -563,6 +556,13 @@ private class StdOStreamOutNonMember extends DataFlowFunction, TaintFunction { } } +/** + * The `std::basic_stringstream` template class instantiations. + */ +private class StdBasicStringStream extends ClassTemplateInstantiation { + StdBasicStringStream() { this.hasQualifiedName(["std", "bsl"], "basic_stringstream") } +} + /** * Additional model for `std::stringstream` constructors that take a string * input parameter. From 26324227832ef755a8620191e7ee3df728cc8639 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Fri, 12 Feb 2021 19:28:12 +0100 Subject: [PATCH 332/429] Python: Add FP test for unknown argument in string format Reported in https://github.com/github/codeql/issues/2650 I found this during a bit of spring cleaning in my working directory. As this doesn't have any immediate security implications, I don't know when we'll get round to fixing it, but it can't hurt to have the test case checked in. --- .../UnusedNamedArgumentIn3101Format.expected | 3 +++ .../Formatting/unknown_format_string.py | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py diff --git a/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected index 849920f8c07..462a9ed3992 100644 --- a/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected +++ b/python/ql/test/query-tests/Expressions/Formatting/UnusedNamedArgumentIn3101Format.expected @@ -6,3 +6,6 @@ | test.py:45:1:45:35 | format() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:39:14:39:18 | Str | any format used. | | test.py:46:1:46:34 | Attribute() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:37:14:37:18 | Str | any format used. | | test.py:46:1:46:34 | Attribute() | Surplus named argument for string format. An argument named 'z' is provided, but it is not required by $@. | test.py:39:14:39:18 | Str | any format used. | +| unknown_format_string.py:9:12:9:30 | Attribute() | Surplus named argument for string format. An argument named 'b' is provided, but it is not required by $@. | unknown_format_string.py:8:15:8:19 | Str | format "{a}" | +| unknown_format_string.py:17:12:17:30 | Attribute() | Surplus named argument for string format. An argument named 'b' is provided, but it is not required by $@. | unknown_format_string.py:16:15:16:19 | Str | format "{a}" | +| unknown_format_string.py:25:12:25:30 | Attribute() | Surplus named argument for string format. An argument named 'b' is provided, but it is not required by $@. | unknown_format_string.py:24:15:24:19 | Str | format "{a}" | diff --git a/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py b/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py new file mode 100644 index 00000000000..a3b32a504db --- /dev/null +++ b/python/ql/test/query-tests/Expressions/Formatting/unknown_format_string.py @@ -0,0 +1,25 @@ +# FP Reported in https://github.com/github/codeql/issues/2650 + +def possibly_unknown_format_string1(x): + user_specified = unknown_function() + if user_specified: + fmt = user_specified + else: + fmt = "{a}" + return fmt.format(a=1,b=2) + +def possibly_unknown_format_string2(x): + user_specified = input() + if user_specified: + fmt = user_specified + else: + fmt = "{a}" + return fmt.format(a=1,b=2) + + +def possibly_unknown_format_string3(x): + if unknown_function(): + fmt = input() + else: + fmt = "{a}" + return fmt.format(a=1,b=2) From 782f4bc3e20a6f7904adf8b7facb1fd47bb364f6 Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Fri, 12 Feb 2021 13:38:55 -0800 Subject: [PATCH 333/429] Fixing shared .qhelp issue (renaming to .qhelp.inc)& addressing a fix --- .../ModifiedFnvFunctionDetection.qhelp | 2 +- .../NumberOfKnownCommandsAboveThreshold.qhelp | 2 +- .../NumberOfKnownHashesAboveThreshold.qhelp | 2 +- .../NumberOfKnownLiteralsAboveThreshold.qhelp | 2 +- ...NumberOfKnownMethodNamesAboveThreshold.qhelp | 2 +- .../{Solorigate.qhelp => Solorigate.qhelp.inc} | 0 .../SwallowEverythingExceptionHandler.qhelp | 2 +- .../Cryptography/NonCryptographicHashes.qll | 17 ++++------------- 8 files changed, 10 insertions(+), 19 deletions(-) rename csharp/ql/src/experimental/Security Features/campaign/Solorigate/{Solorigate.qhelp => Solorigate.qhelp.inc} (100%) diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp index 0b0e1333eb1..dab8e033caa 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/ModifiedFnvFunctionDetection.qhelp @@ -7,6 +7,6 @@

    This query detects FNV-like hash calculations where there is an additional XOR (with any static value) after the hash calculation loop.

    - +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp index 9417cbb2645..adad2a1ba04 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownCommandsAboveThreshold.qhelp @@ -7,6 +7,6 @@

    By themselves, the names of these enumeration constants are not malicious, so the query only detects enumerations that includes at least 10 of the 18 Solorigate commands.

    - +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp index a5fca70869b..3188a45d7a6 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownHashesAboveThreshold.qhelp @@ -8,6 +8,6 @@

    Please notice that by themselves these literals are not malign, but several of the values together would be less likely to be coincidental.

    - +
    \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp index 5a275eeadba..fe6e1d0a936 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownLiteralsAboveThreshold.qhelp @@ -8,6 +8,6 @@

    Please notice that by themselves these literals are not malign.

    - + \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp index f75f1e27097..d99821def93 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/NumberOfKnownMethodNamesAboveThreshold.qhelp @@ -8,6 +8,6 @@

    Please notice that by themselves these method names are not malign.

    - + \ No newline at end of file diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp.inc similarity index 100% rename from csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp rename to csharp/ql/src/experimental/Security Features/campaign/Solorigate/Solorigate.qhelp.inc diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp index 7be5a1f902e..7c52a5e2e5e 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate/SwallowEverythingExceptionHandler.qhelp @@ -7,6 +7,6 @@

    This query detects all generic exception empty catch blocks, but it is strongly suggested that the results for cs/catch-of-all-exceptions also be reviewed in the event that a malicious swallow everything exception handler was not empty

    - + \ No newline at end of file diff --git a/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll b/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll index 4e6c40205ec..03585e32a77 100644 --- a/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll +++ b/csharp/ql/src/experimental/code/csharp/Cryptography/NonCryptographicHashes.qll @@ -74,19 +74,10 @@ predicate isCallableAPotentialNonCryptographicHashFunction(Callable callable, Pa exists(Variable v, Expr op1, Expr op2, LoopStmt loop | maybeANonCryptogrphicHash(callable, v, op1, op2, loop) and callable.getAParameter() = param and - ( - param.getAnAccess() = op1.(Operation).getAnOperand().getAChild*() - or - param.getAnAccess() = op2.(Operation).getAnOperand().getAChild*() - or - exists(Node source, Node sink | - ( - sink.asExpr() = op1.(Operation).getAChild*() or - sink.asExpr() = op2.(Operation).getAChild*() - ) and - source.asExpr() = param.getAnAccess() and - DataFlow::localFlow(source, sink) - ) + exists(ParameterNode p, ExprNode n | + p.getParameter() = param and + localFlow(p, n) and + n.getExpr() in [op1.(Operation).getAChild*(), op2.(Operation).getAChild*()] ) ) } From 1d007b6e7251f09954e8e243e7555e3064d5dbaf Mon Sep 17 00:00:00 2001 From: yo-h <55373593+yo-h@users.noreply.github.com> Date: Sun, 14 Feb 2021 21:42:58 -0500 Subject: [PATCH 334/429] Java: delete two test cases as per code review --- .../query-tests/ContinueInFalseLoop/A.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/java/ql/test/query-tests/ContinueInFalseLoop/A.java b/java/ql/test/query-tests/ContinueInFalseLoop/A.java index 911d4146a66..51f381b94c8 100644 --- a/java/ql/test/query-tests/ContinueInFalseLoop/A.java +++ b/java/ql/test/query-tests/ContinueInFalseLoop/A.java @@ -30,21 +30,21 @@ public class A { break; } while (c.cond()); - // --- while, for loops --- - while (c.cond()) { - if (c.cond()) - continue; // GOOD [never reached, if the condition changed so it was then the result would no longer apply] - if (c.cond()) - break; - } - for (i = 0; c.cond(); i++) { - if (c.cond()) - continue; // GOOD [never reached, if the condition changed so it was then the result would no longer apply] - if (c.cond()) - break; - } + + + + + + + + + + + + + // --- nested loops --- From 91f277681a467ea2dd4a6d7fdbc9907804a06587 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 15 Feb 2021 09:59:04 +0100 Subject: [PATCH 335/429] fix typo in ApolloClientRequest Co-authored-by: Esben Sparre Andreasen --- .../ql/src/semmle/javascript/frameworks/ClientRequests.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index 34f878c125f..ebfdc874f64 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -844,8 +844,8 @@ module ClientRequest { /** * A model of a URL request made using apollo-client. */ - class ApolloClientRequeist extends ClientRequest::Range, API::InvokeNode { - ApolloClientRequeist() { this = apolloUriCallee().getAnInvocation() } + class ApolloClientRequest extends ClientRequest::Range, API::InvokeNode { + ApolloClientRequest() { this = apolloUriCallee().getAnInvocation() } override DataFlow::Node getUrl() { result = getParameter(0).getMember("uri").getARhs() } From 1a4f370d1507c693dc507cfa54b2976c00b2e32e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:00:28 +0100 Subject: [PATCH 336/429] C#: Fix formatting issues --- csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs | 9 +++++++-- .../Semmle.Extraction.CIL.Driver/ExtractorOptions.cs | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index 2f16872dd74..c5d65794fb5 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -45,6 +45,7 @@ namespace Semmle.Autobuild.Shared private readonly SolutionFile? solution; private readonly IEnumerable includedProjects; + public override IEnumerable IncludedProjects => includedProjects; public IEnumerable Configurations => @@ -84,8 +85,12 @@ namespace Semmle.Autobuild.Shared .ToArray(); } - private IEnumerable ToolsVersions => includedProjects.Where(p => p.ValidToolsVersion).Select(p => p.ToolsVersion); + private IEnumerable ToolsVersions => includedProjects + .Where(p => p.ValidToolsVersion) + .Select(p => p.ToolsVersion); - public Version ToolsVersion => ToolsVersions.Any() ? ToolsVersions.Max() : new Version(); + public Version ToolsVersion => ToolsVersions.Any() + ? ToolsVersions.Max() + : new Version(); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs b/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs index 9964ff5bf0c..75405d562fe 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/ExtractorOptions.cs @@ -163,7 +163,7 @@ namespace Semmle.Extraction.CIL.Driver } private readonly HashSet filesAnalyzed = new HashSet(); - public HashSet MissingReferences {get;} = new HashSet(); + public HashSet MissingReferences { get; } = new HashSet(); } /// From a75306acbd85b66d797e76543e294aea97b4fd60 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:00:52 +0100 Subject: [PATCH 337/429] C#: Remove warnings from MdProvider --- csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs index c6c943032a6..fc22f1f6e94 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/MdProvider.cs @@ -2,6 +2,8 @@ using System; using Microsoft.DiaSymReader; using System.Reflection; +#pragma warning disable IDE0060, CA1822 + namespace Semmle.Extraction.PDB { /// @@ -31,3 +33,5 @@ namespace Semmle.Extraction.PDB throw new NotImplementedException(); } } + +#pragma warning restore From fc3e6526ce7407dda5c2be3305cb208b909f6bcf Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:03:06 +0100 Subject: [PATCH 338/429] C#: Remove IExtractionScope.FromSource --- csharp/extractor/Semmle.Extraction/AssemblyScope.cs | 2 -- csharp/extractor/Semmle.Extraction/Context.cs | 2 +- csharp/extractor/Semmle.Extraction/IExtractionScope.cs | 2 -- csharp/extractor/Semmle.Extraction/SourceScope.cs | 2 -- 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction/AssemblyScope.cs b/csharp/extractor/Semmle.Extraction/AssemblyScope.cs index 84c117d17c4..27c9377bb30 100644 --- a/csharp/extractor/Semmle.Extraction/AssemblyScope.cs +++ b/csharp/extractor/Semmle.Extraction/AssemblyScope.cs @@ -21,7 +21,5 @@ namespace Semmle.Extraction public bool InScope(ISymbol symbol) => SymbolEqualityComparer.Default.Equals(symbol.ContainingAssembly, assembly) || SymbolEqualityComparer.Default.Equals(symbol, assembly); - - public bool FromSource => false; } } diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index e6b4826f2ef..1ebbdf72ea4 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -242,7 +242,7 @@ namespace Semmle.Extraction ShouldAddAssemblyTrapPrefix = addAssemblyTrapPrefix; } - public bool FromSource => scope.FromSource; + public bool FromSource => scope is SourceScope; public ICommentGenerator CommentGenerator { get; } = new CommentProcessor(); diff --git a/csharp/extractor/Semmle.Extraction/IExtractionScope.cs b/csharp/extractor/Semmle.Extraction/IExtractionScope.cs index 78b4a29d0d1..f12823b3f96 100644 --- a/csharp/extractor/Semmle.Extraction/IExtractionScope.cs +++ b/csharp/extractor/Semmle.Extraction/IExtractionScope.cs @@ -22,7 +22,5 @@ namespace Semmle.Extraction /// /// The path to populate. bool InFileScope(string path); - - bool FromSource { get; } } } diff --git a/csharp/extractor/Semmle.Extraction/SourceScope.cs b/csharp/extractor/Semmle.Extraction/SourceScope.cs index 48a89decba9..fba816f6363 100644 --- a/csharp/extractor/Semmle.Extraction/SourceScope.cs +++ b/csharp/extractor/Semmle.Extraction/SourceScope.cs @@ -19,7 +19,5 @@ namespace Semmle.Extraction public bool InFileScope(string path) => path == SourceTree.FilePath; public bool InScope(ISymbol symbol) => symbol.Locations.Any(loc => loc.SourceTree == SourceTree); - - public bool FromSource => true; } } From 6cdec2d30ecb5624e2505b768587a841159c4f36 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:09:34 +0100 Subject: [PATCH 339/429] C#: Remove 'extractor.CreateContext' factory method --- .../Semmle.Extraction.CIL/Entities/Assembly.cs | 2 +- .../Semmle.Extraction.CSharp/Analyser.cs | 6 +++--- csharp/extractor/Semmle.Extraction/Context.cs | 13 +++++-------- csharp/extractor/Semmle.Extraction/Extractor.cs | 15 --------------- 4 files changed, 9 insertions(+), 27 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs index 8a843f1672d..5c0a834909c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs @@ -136,7 +136,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile = trapWriter.TrapFile; if (nocache || !System.IO.File.Exists(trapFile)) { - var cx = extractor.CreateContext(null, trapWriter, null, false); + var cx = new Extraction.Context(extractor, trapWriter); ExtractCIL(cx, assemblyPath, extractPdbs); extracted = true; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index f9e0d7c3806..ee2326648ed 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -230,7 +230,7 @@ namespace Semmle.Extraction.CSharp var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath); var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: false); compilationTrapFile = trapWriter; // Dispose later - var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); + var cx = new Context(extractor, compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); compilationEntity = Entities.Compilation.Create(cx); } @@ -285,7 +285,7 @@ namespace Semmle.Extraction.CSharp if (c.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly) { - var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); + var cx = new Context(extractor, c, trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix); foreach (var module in assembly.Modules) { @@ -371,7 +371,7 @@ namespace Semmle.Extraction.CSharp if (!upToDate) { - var cx = extractor.CreateContext(compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); + var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix); // Ensure that the file itself is populated in case the source file is totally empty var root = tree.GetRoot(); Extraction.Entities.File.Create(cx, root.SyntaxTree.FilePath); diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 1ebbdf72ea4..af13b5d3b76 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -225,14 +225,6 @@ namespace Semmle.Extraction /// public Compilation Compilation { get; } - /// - /// Create a new context, one per source file/assembly. - /// - /// The extractor. - /// The Roslyn compilation. - /// Name of the source/dll file. - /// Defines which symbols are included in the trap file (e.g. AssemblyScope or SourceScope) - /// Whether to add assembly prefixes to TRAP labels. public Context(IExtractor e, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix) { Extractor = e; @@ -242,6 +234,11 @@ namespace Semmle.Extraction ShouldAddAssemblyTrapPrefix = addAssemblyTrapPrefix; } + public Context(IExtractor e, TrapWriter trapWriter) + : this(e, null, trapWriter, null, false) + { + } + public bool FromSource => scope is SourceScope; public ICommentGenerator CommentGenerator { get; } = new CommentProcessor(); diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index 4f5c27f3a90..33ec2d72915 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -83,16 +83,6 @@ namespace Semmle.Extraction /// The path transformer to apply. ///
    PathTransformer PathTransformer { get; } - - /// - /// Creates a new context. - /// - /// The C# compilation. - /// The trap writer. - /// The extraction scope (what to include in this trap file). - /// Whether to add assembly prefixes to TRAP labels. - /// - Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix); } /// @@ -189,11 +179,6 @@ namespace Semmle.Extraction } } - public Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix) - { - return new Context(this, c, trapWriter, scope, addAssemblyTrapPrefix); - } - public IEnumerable MissingTypes => missingTypes; public IEnumerable MissingNamespaces => missingNamespaces; From 9ddeff80bf5e0ce621b58674650f509413b8fe71 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:12:49 +0100 Subject: [PATCH 340/429] Remove useless 'IExtractor' interface --- .../Semmle.Extraction.CSharp/Analyser.cs | 2 +- csharp/extractor/Semmle.Extraction/Context.cs | 8 +- csharp/extractor/Semmle.Extraction/Entity.cs | 2 +- .../extractor/Semmle.Extraction/Extractor.cs | 83 +------------------ 4 files changed, 7 insertions(+), 88 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs index ee2326648ed..b04b429993d 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Analyser.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp /// public sealed class Analyser : IDisposable { - private IExtractor extractor; + private Extraction.Extractor extractor; private CSharpCompilation compilation; private Layout layout; private bool init; diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index af13b5d3b76..c3eaa80d933 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction /// /// Access various extraction functions, e.g. logger, trap writer. /// - public IExtractor Extractor { get; } + public Extractor Extractor { get; } /// /// The program database provided by Roslyn. @@ -51,7 +51,7 @@ namespace Semmle.Extraction // A recursion guard against writing to the trap file whilst writing an id to the trap file. private bool writingLabel = false; - public void DefineLabel(IEntity entity, TextWriter trapFile, IExtractor extractor) + public void DefineLabel(IEntity entity, TextWriter trapFile, Extractor extractor) { if (writingLabel) { @@ -225,7 +225,7 @@ namespace Semmle.Extraction /// public Compilation Compilation { get; } - public Context(IExtractor e, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix) + public Context(Extractor e, Compilation c, TrapWriter trapWriter, IExtractionScope scope, bool addAssemblyTrapPrefix) { Extractor = e; Compilation = c; @@ -234,7 +234,7 @@ namespace Semmle.Extraction ShouldAddAssemblyTrapPrefix = addAssemblyTrapPrefix; } - public Context(IExtractor e, TrapWriter trapWriter) + public Context(Extractor e, TrapWriter trapWriter) : this(e, null, trapWriter, null, false) { } diff --git a/csharp/extractor/Semmle.Extraction/Entity.cs b/csharp/extractor/Semmle.Extraction/Entity.cs index 5479c93fee9..8839b6ede2a 100644 --- a/csharp/extractor/Semmle.Extraction/Entity.cs +++ b/csharp/extractor/Semmle.Extraction/Entity.cs @@ -137,7 +137,7 @@ namespace Semmle.Extraction where TSymbol : ISymbol where TEntity : ICachedEntity => cx.CreateEntityFromSymbol(factory, init); - public static void DefineLabel(this IEntity entity, TextWriter trapFile, IExtractor extractor) + public static void DefineLabel(this IEntity entity, TextWriter trapFile, Extractor extractor) { trapFile.WriteLabel(entity); trapFile.Write("="); diff --git a/csharp/extractor/Semmle.Extraction/Extractor.cs b/csharp/extractor/Semmle.Extraction/Extractor.cs index 33ec2d72915..6e031fbca52 100644 --- a/csharp/extractor/Semmle.Extraction/Extractor.cs +++ b/csharp/extractor/Semmle.Extraction/Extractor.cs @@ -4,91 +4,10 @@ using Semmle.Util.Logging; namespace Semmle.Extraction { - /// - /// Provides common extraction functions for use during extraction. - /// - /// - /// - /// This is held in the passed to each entity. - /// - public interface IExtractor - { - /// - /// Logs a message (to csharp.log). - /// Increases the error count if msg.severity is Error. - /// - /// The message to log. - void Message(Message msg); - - /// - /// Cache assembly names. - /// - /// The assembly name. - /// The file defining the assembly. - void SetAssemblyFile(string assembly, string file); - - /// - /// Maps assembly names to file names. - /// - /// The assembly name - /// The file defining the assmebly. - string GetAssemblyFile(string assembly); - - /// - /// How many errors encountered during extraction? - /// - int Errors { get; } - - /// - /// The extraction is standalone - meaning there will be a lot of errors. - /// - bool Standalone { get; } - - /// - /// Record a new error type. - /// - /// The display name of the type, qualified where possible. - /// If the missing type was referenced from a source file. - void MissingType(string fqn, bool fromSource); - - /// - /// Record an unresolved `using namespace` directive. - /// - /// The full name of the namespace. - /// If the missing namespace was referenced from a source file. - void MissingNamespace(string fqn, bool fromSource); - - /// - /// The list of missing types. - /// - IEnumerable MissingTypes { get; } - - /// - /// The list of missing namespaces. - /// - IEnumerable MissingNamespaces { get; } - - /// - /// The full path of the generated DLL/EXE. - /// null if not specified. - /// - string OutputPath { get; } - - /// - /// The object used for logging. - /// - ILogger Logger { get; } - - /// - /// The path transformer to apply. - /// - PathTransformer PathTransformer { get; } - } - /// /// Implementation of the main extractor state. /// - public class Extractor : IExtractor + public class Extractor { public bool Standalone { From 5ce5a96cb6cb6b181f796ada0b185631f144fac6 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:15:33 +0100 Subject: [PATCH 341/429] Remove 'ContextExtensions' --- csharp/extractor/Semmle.Extraction/Context.cs | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index c3eaa80d933..99e877f5ef2 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -457,42 +457,36 @@ namespace Semmle.Extraction new Entities.ExtractionMessage(this, msg); Extractor.Message(msg); } - } - public static class ContextExtensions - { /// /// Signal an error in the program model. /// - /// The context. /// The syntax node causing the failure. /// The error message. - public static void ModelError(this Context cx, SyntaxNode node, string msg) + public void ModelError(SyntaxNode node, string msg) { - if (!cx.Extractor.Standalone) + if (!Extractor.Standalone) throw new InternalError(node, msg); } /// /// Signal an error in the program model. /// - /// The context. /// Symbol causing the error. /// The error message. - public static void ModelError(this Context cx, ISymbol symbol, string msg) + public void ModelError(ISymbol symbol, string msg) { - if (!cx.Extractor.Standalone) + if (!Extractor.Standalone) throw new InternalError(symbol, msg); } /// /// Signal an error in the program model. /// - /// The context. /// The error message. - public static void ModelError(this Context cx, string msg) + public void ModelError(string msg) { - if (!cx.Extractor.Standalone) + if (!Extractor.Standalone) throw new InternalError(msg); } @@ -500,11 +494,10 @@ namespace Semmle.Extraction /// Tries the supplied action , and logs an uncaught /// exception error if the action fails. /// - /// The context. /// Optional syntax node for error reporting. /// Optional symbol for error reporting. /// The action to perform. - public static void Try(this Context context, SyntaxNode? node, ISymbol? symbol, Action a) + public void Try(SyntaxNode? node, ISymbol? symbol, Action a) { try { @@ -516,33 +509,32 @@ namespace Semmle.Extraction if (node != null) { - message = Message.Create(context, ex.Message, node, ex.StackTrace); + message = Message.Create(this, ex.Message, node, ex.StackTrace); } else if (symbol != null) { - message = Message.Create(context, ex.Message, symbol, ex.StackTrace); + message = Message.Create(this, ex.Message, symbol, ex.StackTrace); } else if (ex is InternalError ie) { - message = new Message(ie.Text, ie.EntityText, Entities.Location.Create(context, ie.Location), ex.StackTrace); + message = new Message(ie.Text, ie.EntityText, Entities.Location.Create(this, ie.Location), ex.StackTrace); } else { - message = new Message($"Uncaught exception. {ex.Message}", null, Entities.Location.Create(context), ex.StackTrace); + message = new Message($"Uncaught exception. {ex.Message}", null, Entities.Location.Create(this), ex.StackTrace); } - context.ExtractionError(message); + ExtractionError(message); } } /// /// Write the given tuple to the trap file. /// - /// Extractor context. /// Tuple to write. - public static void Emit(this Context cx, Tuple tuple) + public void Emit(Tuple tuple) { - cx.TrapWriter.Emit(tuple); + TrapWriter.Emit(tuple); } } } From e8fd6e11128c74496d4259ed964fb743bbc58b5d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:23:15 +0100 Subject: [PATCH 342/429] Move classes to seperate files --- .../Entities/CallTypeExtensions.cs | 27 ++ .../Entities/Expression.cs | 320 ------------------ .../Entities/ExpressionInfo.cs | 36 ++ .../Entities/ExpressionNodeInfo.cs | 189 +++++++++++ .../Entities/Expression`1.cs | 34 ++ .../Entities/IExpressionInfo.cs | 53 +++ .../Entities/IExpressionParentEntity.cs | 10 + .../Entities/IStatementParentEntity.cs | 10 + .../Entities/Statement.cs | 51 --- .../Entities/Statement`1.cs | 47 +++ 10 files changed, 406 insertions(+), 371 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs new file mode 100644 index 00000000000..6b9564e49dc --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CallTypeExtensions.cs @@ -0,0 +1,27 @@ +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal static class CallTypeExtensions + { + /// + /// Adjust the expression kind to match this call type. + /// + public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) + { + if (k == ExprKind.ADDRESS_OF) + { + return k; + } + + switch (ct) + { + case Expression.CallType.Dynamic: + case Expression.CallType.UserOperator: + return ExprKind.OPERATOR_INVOCATION; + default: + return k; + } + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 6c738da3af1..e343414a4cb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -2,8 +2,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Entities.Expressions; -using Semmle.Extraction.CSharp.Populators; -using Semmle.Extraction.Entities; using Semmle.Extraction.Kinds; using System; using System.IO; @@ -11,14 +9,6 @@ using System.Linq; namespace Semmle.Extraction.CSharp.Entities { - public interface IExpressionParentEntity : IEntity - { - /// - /// Whether this entity is the parent of a top-level expression. - /// - bool IsTopLevelParent { get; } - } - internal class Expression : FreshEntity, IExpressionParentEntity { private readonly IExpressionInfo info; @@ -308,314 +298,4 @@ namespace Semmle.Extraction.CSharp.Entities public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } - - internal static class CallTypeExtensions - { - /// - /// Adjust the expression kind to match this call type. - /// - public static ExprKind AdjustKind(this Expression.CallType ct, ExprKind k) - { - if (k == ExprKind.ADDRESS_OF) - { - return k; - } - - switch (ct) - { - case Expression.CallType.Dynamic: - case Expression.CallType.UserOperator: - return ExprKind.OPERATOR_INVOCATION; - default: - return k; - } - } - } - - internal abstract class Expression : Expression - where TExpressionSyntax : ExpressionSyntax - { - public TExpressionSyntax Syntax { get; } - - protected Expression(ExpressionNodeInfo info) - : base(info) - { - Syntax = (TExpressionSyntax)info.Node; - } - - /// - /// Populates expression-type specific relations in the trap file. The general relations - /// expressions and expr_location are populated by the constructor - /// (should not fail), so even if expression-type specific population fails (e.g., in - /// standalone extraction), the expression created via - /// will - /// still be valid. - /// - protected abstract void PopulateExpression(TextWriter trapFile); - - protected new Expression TryPopulate() - { - cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer)); - return this; - } - } - - /// - /// Holds all information required to create an Expression entity. - /// - internal interface IExpressionInfo - { - Context Context { get; } - - /// - /// The type of the expression. - /// - AnnotatedTypeSymbol? Type { get; } - - /// - /// The location of the expression. - /// - Extraction.Entities.Location Location { get; } - - /// - /// The kind of the expression. - /// - ExprKind Kind { get; } - - /// - /// The parent of the expression. - /// - IExpressionParentEntity Parent { get; } - - /// - /// The child index of the expression. - /// - int Child { get; } - - /// - /// Holds if this is an implicit expression. - /// - bool IsCompilerGenerated { get; } - - /// - /// Gets a string representation of the value. - /// null is encoded as the string "null". - /// If the expression does not have a value, then this - /// is null. - /// - string ExprValue { get; } - - NullableFlowState FlowState { get; } - } - - /// - /// Explicitly constructed expression information. - /// - internal class ExpressionInfo : IExpressionInfo - { - public Context Context { get; } - public AnnotatedTypeSymbol? Type { get; } - public Extraction.Entities.Location Location { get; } - public ExprKind Kind { get; } - public IExpressionParentEntity Parent { get; } - public int Child { get; } - public bool IsCompilerGenerated { get; } - public string ExprValue { get; } - - public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, - IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value) - { - Context = cx; - Type = type; - Location = location; - Kind = kind; - Parent = parent; - Child = child; - ExprValue = value; - IsCompilerGenerated = isCompilerGenerated; - } - - // Synthetic expressions don't have a flow state. - public NullableFlowState FlowState => NullableFlowState.None; - } - - /// - /// Expression information constructed from a syntax node. - /// - internal class ExpressionNodeInfo : IExpressionInfo - { - public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) : - this(cx, node, parent, child, cx.GetTypeInfo(node)) - { - } - - public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child, TypeInfo typeInfo) - { - Context = cx; - Node = node; - Parent = parent; - Child = child; - TypeInfo = typeInfo; - Conversion = cx.GetModel(node).GetConversion(node); - } - - public Context Context { get; } - public ExpressionSyntax Node { get; private set; } - public IExpressionParentEntity Parent { get; set; } - public int Child { get; set; } - public TypeInfo TypeInfo { get; } - public Microsoft.CodeAnalysis.CSharp.Conversion Conversion { get; } - - public AnnotatedTypeSymbol ResolvedType => new AnnotatedTypeSymbol(TypeInfo.Type.DisambiguateType(), TypeInfo.Nullability.Annotation); - public AnnotatedTypeSymbol ConvertedType => new AnnotatedTypeSymbol(TypeInfo.ConvertedType.DisambiguateType(), TypeInfo.ConvertedNullability.Annotation); - - private AnnotatedTypeSymbol? cachedType; - private bool cachedTypeSet; - public AnnotatedTypeSymbol? Type - { - get - { - if (cachedTypeSet) - return cachedType; - - var type = ResolvedType; - - if (type.Symbol == null) - type.Symbol = (TypeInfo.Type ?? TypeInfo.ConvertedType).DisambiguateType(); - - // Roslyn workaround: It can't work out the type of "new object[0]" - // Clearly a bug. - if (type.Symbol?.TypeKind == Microsoft.CodeAnalysis.TypeKind.Error) - { - if (Node is ArrayCreationExpressionSyntax arrayCreation) - { - var elementType = Context.GetType(arrayCreation.Type.ElementType); - - if (elementType.Symbol != null) - // There seems to be no way to create an array with a nullable element at present. - return new AnnotatedTypeSymbol(Context.Compilation.CreateArrayTypeSymbol(elementType.Symbol, arrayCreation.Type.RankSpecifiers.Count), NullableAnnotation.NotAnnotated); - } - - Context.ModelError(Node, "Failed to determine type"); - } - - cachedType = type; - cachedTypeSet = true; - - return type; - } - } - - private Microsoft.CodeAnalysis.Location location; - - public Microsoft.CodeAnalysis.Location CodeAnalysisLocation - { - get - { - if (location == null) - location = Node.FixedLocation(); - return location; - } - set - { - location = value; - } - } - - public SemanticModel Model => Context.GetModel(Node); - - public string ExprValue - { - get - { - var c = Model.GetConstantValue(Node); - if (c.HasValue) - { - return Expression.ValueAsString(c.Value); - } - - if (TryGetBoolValueFromLiteral(out var val)) - { - return Expression.ValueAsString(val); - } - - return null; - } - } - - private Extraction.Entities.Location cachedLocation; - - public Extraction.Entities.Location Location - { - get - { - if (cachedLocation == null) - cachedLocation = Context.Create(CodeAnalysisLocation); - return cachedLocation; - } - - set - { - cachedLocation = value; - } - } - - public ExprKind Kind { get; set; } = ExprKind.UNKNOWN; - - public bool IsCompilerGenerated { get; set; } - - public ExpressionNodeInfo SetParent(IExpressionParentEntity parent, int child) - { - Parent = parent; - Child = child; - return this; - } - - public ExpressionNodeInfo SetKind(ExprKind kind) - { - Kind = kind; - return this; - } - - public ExpressionNodeInfo SetType(AnnotatedTypeSymbol? type) - { - cachedType = type; - cachedTypeSet = true; - return this; - } - - public ExpressionNodeInfo SetNode(ExpressionSyntax node) - { - Node = node; - return this; - } - - private SymbolInfo cachedSymbolInfo; - - public SymbolInfo SymbolInfo - { - get - { - if (cachedSymbolInfo.Symbol == null && cachedSymbolInfo.CandidateReason == CandidateReason.None) - cachedSymbolInfo = Model.GetSymbolInfo(Node); - return cachedSymbolInfo; - } - } - - public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; - - private bool TryGetBoolValueFromLiteral(out bool val) - { - var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression); - var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression); - - val = isTrue; - return isTrue || isFalse; - } - - public bool IsBoolLiteral() - { - return TryGetBoolValueFromLiteral(out var _); - } - } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs new file mode 100644 index 00000000000..feb1eaa2d93 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionInfo.cs @@ -0,0 +1,36 @@ +using Microsoft.CodeAnalysis; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Explicitly constructed expression information. + /// + internal class ExpressionInfo : IExpressionInfo + { + public Context Context { get; } + public AnnotatedTypeSymbol? Type { get; } + public Extraction.Entities.Location Location { get; } + public ExprKind Kind { get; } + public IExpressionParentEntity Parent { get; } + public int Child { get; } + public bool IsCompilerGenerated { get; } + public string ExprValue { get; } + + public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind, + IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value) + { + Context = cx; + Type = type; + Location = location; + Kind = kind; + Parent = parent; + Child = child; + ExprValue = value; + IsCompilerGenerated = isCompilerGenerated; + } + + // Synthetic expressions don't have a flow state. + public NullableFlowState FlowState => NullableFlowState.None; + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs new file mode 100644 index 00000000000..febb84ded7c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs @@ -0,0 +1,189 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Extraction.CSharp.Populators; +using Semmle.Extraction.Entities; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Expression information constructed from a syntax node. + /// + internal class ExpressionNodeInfo : IExpressionInfo + { + public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child) : + this(cx, node, parent, child, cx.GetTypeInfo(node)) + { + } + + public ExpressionNodeInfo(Context cx, ExpressionSyntax node, IExpressionParentEntity parent, int child, TypeInfo typeInfo) + { + Context = cx; + Node = node; + Parent = parent; + Child = child; + TypeInfo = typeInfo; + Conversion = cx.GetModel(node).GetConversion(node); + } + + public Context Context { get; } + public ExpressionSyntax Node { get; private set; } + public IExpressionParentEntity Parent { get; set; } + public int Child { get; set; } + public TypeInfo TypeInfo { get; } + public Microsoft.CodeAnalysis.CSharp.Conversion Conversion { get; } + + public AnnotatedTypeSymbol ResolvedType => new AnnotatedTypeSymbol(TypeInfo.Type.DisambiguateType(), TypeInfo.Nullability.Annotation); + public AnnotatedTypeSymbol ConvertedType => new AnnotatedTypeSymbol(TypeInfo.ConvertedType.DisambiguateType(), TypeInfo.ConvertedNullability.Annotation); + + private AnnotatedTypeSymbol? cachedType; + private bool cachedTypeSet; + public AnnotatedTypeSymbol? Type + { + get + { + if (cachedTypeSet) + return cachedType; + + var type = ResolvedType; + + if (type.Symbol == null) + type.Symbol = (TypeInfo.Type ?? TypeInfo.ConvertedType).DisambiguateType(); + + // Roslyn workaround: It can't work out the type of "new object[0]" + // Clearly a bug. + if (type.Symbol?.TypeKind == Microsoft.CodeAnalysis.TypeKind.Error) + { + if (Node is ArrayCreationExpressionSyntax arrayCreation) + { + var elementType = Context.GetType(arrayCreation.Type.ElementType); + + if (elementType.Symbol != null) + // There seems to be no way to create an array with a nullable element at present. + return new AnnotatedTypeSymbol(Context.Compilation.CreateArrayTypeSymbol(elementType.Symbol, arrayCreation.Type.RankSpecifiers.Count), NullableAnnotation.NotAnnotated); + } + + Context.ModelError(Node, "Failed to determine type"); + } + + cachedType = type; + cachedTypeSet = true; + + return type; + } + } + + private Microsoft.CodeAnalysis.Location location; + + public Microsoft.CodeAnalysis.Location CodeAnalysisLocation + { + get + { + if (location == null) + location = Node.FixedLocation(); + return location; + } + set + { + location = value; + } + } + + public SemanticModel Model => Context.GetModel(Node); + + public string ExprValue + { + get + { + var c = Model.GetConstantValue(Node); + if (c.HasValue) + { + return Expression.ValueAsString(c.Value); + } + + if (TryGetBoolValueFromLiteral(out var val)) + { + return Expression.ValueAsString(val); + } + + return null; + } + } + + private Extraction.Entities.Location cachedLocation; + + public Extraction.Entities.Location Location + { + get + { + if (cachedLocation == null) + cachedLocation = Context.Create(CodeAnalysisLocation); + return cachedLocation; + } + + set + { + cachedLocation = value; + } + } + + public ExprKind Kind { get; set; } = ExprKind.UNKNOWN; + + public bool IsCompilerGenerated { get; set; } + + public ExpressionNodeInfo SetParent(IExpressionParentEntity parent, int child) + { + Parent = parent; + Child = child; + return this; + } + + public ExpressionNodeInfo SetKind(ExprKind kind) + { + Kind = kind; + return this; + } + + public ExpressionNodeInfo SetType(AnnotatedTypeSymbol? type) + { + cachedType = type; + cachedTypeSet = true; + return this; + } + + public ExpressionNodeInfo SetNode(ExpressionSyntax node) + { + Node = node; + return this; + } + + private SymbolInfo cachedSymbolInfo; + + public SymbolInfo SymbolInfo + { + get + { + if (cachedSymbolInfo.Symbol == null && cachedSymbolInfo.CandidateReason == CandidateReason.None) + cachedSymbolInfo = Model.GetSymbolInfo(Node); + return cachedSymbolInfo; + } + } + + public NullableFlowState FlowState => TypeInfo.Nullability.FlowState; + + private bool TryGetBoolValueFromLiteral(out bool val) + { + var isTrue = Node.IsKind(SyntaxKind.TrueLiteralExpression); + var isFalse = Node.IsKind(SyntaxKind.FalseLiteralExpression); + + val = isTrue; + return isTrue || isFalse; + } + + public bool IsBoolLiteral() + { + return TryGetBoolValueFromLiteral(out var _); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs new file mode 100644 index 00000000000..c16f0679c10 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs @@ -0,0 +1,34 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal abstract class Expression : Expression + where TExpressionSyntax : ExpressionSyntax + { + public TExpressionSyntax Syntax { get; } + + protected Expression(ExpressionNodeInfo info) + : base(info) + { + Syntax = (TExpressionSyntax)info.Node; + } + + /// + /// Populates expression-type specific relations in the trap file. The general relations + /// expressions and expr_location are populated by the constructor + /// (should not fail), so even if expression-type specific population fails (e.g., in + /// standalone extraction), the expression created via + /// will + /// still be valid. + /// + protected abstract void PopulateExpression(TextWriter trapFile); + + protected new Expression TryPopulate() + { + cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer)); + return this; + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs new file mode 100644 index 00000000000..1a43a6fbd02 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionInfo.cs @@ -0,0 +1,53 @@ +using Microsoft.CodeAnalysis; +using Semmle.Extraction.Kinds; + +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Holds all information required to create an Expression entity. + /// + internal interface IExpressionInfo + { + Context Context { get; } + + /// + /// The type of the expression. + /// + AnnotatedTypeSymbol? Type { get; } + + /// + /// The location of the expression. + /// + Extraction.Entities.Location Location { get; } + + /// + /// The kind of the expression. + /// + ExprKind Kind { get; } + + /// + /// The parent of the expression. + /// + IExpressionParentEntity Parent { get; } + + /// + /// The child index of the expression. + /// + int Child { get; } + + /// + /// Holds if this is an implicit expression. + /// + bool IsCompilerGenerated { get; } + + /// + /// Gets a string representation of the value. + /// null is encoded as the string "null". + /// If the expression does not have a value, then this + /// is null. + /// + string ExprValue { get; } + + NullableFlowState FlowState { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs new file mode 100644 index 00000000000..a8e4df3d6ca --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IExpressionParentEntity.cs @@ -0,0 +1,10 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + public interface IExpressionParentEntity : IEntity + { + /// + /// Whether this entity is the parent of a top-level expression. + /// + bool IsTopLevelParent { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs new file mode 100644 index 00000000000..40bc0f218c0 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/IStatementParentEntity.cs @@ -0,0 +1,10 @@ +namespace Semmle.Extraction.CSharp.Entities +{ + /// + /// Whether this entity is the parent of a top-level statement. + /// + public interface IStatementParentEntity : IEntity + { + bool IsTopLevelParent { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs index 44bd7f80583..7a5bdcd2a58 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs @@ -1,19 +1,8 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Extraction.CSharp.Populators; using Microsoft.CodeAnalysis.CSharp; -using Semmle.Extraction.Entities; -using System.IO; namespace Semmle.Extraction.CSharp.Entities { - /// - /// Whether this entity is the parent of a top-level statement. - /// - public interface IStatementParentEntity : IEntity - { - bool IsTopLevelParent { get; } - } - internal abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity { protected Statement(Context cx) : base(cx) { } @@ -37,44 +26,4 @@ namespace Semmle.Extraction.CSharp.Entities public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel; } - - internal abstract class Statement : Statement where TSyntax : CSharpSyntaxNode - { - protected readonly TSyntax Stmt; - private readonly int child; - private readonly Kinds.StmtKind kind; - private readonly IStatementParentEntity parent; - private readonly Location location; - - protected override CSharpSyntaxNode GetStatementSyntax() => Stmt; - - protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location) - : base(cx) - { - Stmt = stmt; - this.parent = parent; - this.child = child; - this.location = location; - this.kind = kind; - cx.BindComments(this, location.symbol); - } - - protected sealed override void Populate(TextWriter trapFile) - { - trapFile.statements(this, kind); - if (parent.IsTopLevelParent) - trapFile.stmt_parent_top_level(this, child, parent); - else - trapFile.stmt_parent(this, child, parent); - trapFile.stmt_location(this, location); - PopulateStatement(trapFile); - } - - protected abstract void PopulateStatement(TextWriter trapFile); - - protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child) - : this(cx, stmt, kind, parent, child, cx.Create(stmt.FixedLocation())) { } - - public override string ToString() => Label.ToString(); - } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs new file mode 100644 index 00000000000..89b2b1696fd --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs @@ -0,0 +1,47 @@ +using Semmle.Extraction.CSharp.Populators; +using Microsoft.CodeAnalysis.CSharp; +using Semmle.Extraction.Entities; +using System.IO; + +namespace Semmle.Extraction.CSharp.Entities +{ + internal abstract class Statement : Statement where TSyntax : CSharpSyntaxNode + { + protected readonly TSyntax Stmt; + private readonly int child; + private readonly Kinds.StmtKind kind; + private readonly IStatementParentEntity parent; + private readonly Location location; + + protected override CSharpSyntaxNode GetStatementSyntax() => Stmt; + + protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location) + : base(cx) + { + Stmt = stmt; + this.parent = parent; + this.child = child; + this.location = location; + this.kind = kind; + cx.BindComments(this, location.symbol); + } + + protected sealed override void Populate(TextWriter trapFile) + { + trapFile.statements(this, kind); + if (parent.IsTopLevelParent) + trapFile.stmt_parent_top_level(this, child, parent); + else + trapFile.stmt_parent(this, child, parent); + trapFile.stmt_location(this, location); + PopulateStatement(trapFile); + } + + protected abstract void PopulateStatement(TextWriter trapFile); + + protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child) + : this(cx, stmt, kind, parent, child, cx.Create(stmt.FixedLocation())) { } + + public override string ToString() => Label.ToString(); + } +} From 1cd7fd6cf7789ff04a4ce37b90aa852bc73509b4 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:24:29 +0100 Subject: [PATCH 343/429] Simplify 'AstLineCounter' --- .../Semmle.Extraction.CSharp/Populators/Methods.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs index 148160b8815..28a96c24e43 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs @@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Populators public override LineCounts DefaultVisit(SyntaxNode node) { var text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); - return Semmle.Util.LineCounter.ComputeLineCounts(text); + return LineCounter.ComputeLineCounts(text); } public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method) @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Populators var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start); var text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; - return Semmle.Util.LineCounter.ComputeLineCounts(text); + return LineCounter.ComputeLineCounts(text); } public override LineCounts VisitConstructorDeclaration(ConstructorDeclarationSyntax method) @@ -52,14 +52,10 @@ namespace Semmle.Extraction.CSharp.Populators { foreach (var decl in symbol.DeclaringSyntaxReferences) { - cx.NumberOfLines(trapFile, (CSharpSyntaxNode)decl.GetSyntax(), callable); + var node = (CSharpSyntaxNode)decl.GetSyntax(); + var lineCounts = node.Accept(new AstLineCounter()); + trapFile.numlines(callable, lineCounts); } } - - public static void NumberOfLines(this Context cx, TextWriter trapFile, CSharpSyntaxNode node, IEntity callable) - { - var lineCounts = node.Accept(new AstLineCounter()); - trapFile.numlines(callable, lineCounts); - } } } From 6f07230725cc392877bbfae87ecfeb43a316a65d Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:26:28 +0100 Subject: [PATCH 344/429] Relocate 'AstLineCounter' --- .../Method.AstLineCounter.cs} | 14 ++------------ .../Semmle.Extraction.CSharp/Entities/Method.cs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 14 deletions(-) rename csharp/extractor/Semmle.Extraction.CSharp/{Populators/Methods.cs => Entities/Method.AstLineCounter.cs} (79%) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs similarity index 79% rename from csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs rename to csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs index 28a96c24e43..d567b6f6b56 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/Methods.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs @@ -4,9 +4,9 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Util; using System.IO; -namespace Semmle.Extraction.CSharp.Populators +namespace Semmle.Extraction.CSharp.Entities { - public static class MethodExtensions + public abstract partial class Method { private class AstLineCounter : CSharpSyntaxVisitor { @@ -47,15 +47,5 @@ namespace Semmle.Extraction.CSharp.Populators return Visit(node.OperatorToken, node.Body ?? (SyntaxNode)node.ExpressionBody); } } - - public static void NumberOfLines(this Context cx, TextWriter trapFile, ISymbol symbol, IEntity callable) - { - foreach (var decl in symbol.DeclaringSyntaxReferences) - { - var node = (CSharpSyntaxNode)decl.GetSyntax(); - var lineCounts = node.Accept(new AstLineCounter()); - trapFile.numlines(callable, lineCounts); - } - } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index 6a52087e384..f036e373217 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.CSharp.Populators; using System.Collections.Generic; @@ -7,7 +8,7 @@ using System.Linq; namespace Semmle.Extraction.CSharp.Entities { - public abstract class Method : CachedSymbol, IExpressionParentEntity, IStatementParentEntity + public abstract partial class Method : CachedSymbol, IExpressionParentEntity, IStatementParentEntity { protected Method(Context cx, IMethodSymbol init) : base(cx, init) { } @@ -83,11 +84,21 @@ namespace Semmle.Extraction.CSharp.Entities else Expression.Create(Context, expr, this, 0); - Context.NumberOfLines(trapFile, BodyDeclaringSymbol, this); + NumberOfLines(trapFile, BodyDeclaringSymbol, this); }); } } + public static void NumberOfLines(TextWriter trapFile, ISymbol symbol, IEntity callable) + { + foreach (var decl in symbol.DeclaringSyntaxReferences) + { + var node = (CSharpSyntaxNode)decl.GetSyntax(); + var lineCounts = node.Accept(new AstLineCounter()); + trapFile.numlines(callable, lineCounts); + } + } + public void Overrides(TextWriter trapFile) { foreach (var explicitInterface in symbol.ExplicitInterfaceImplementations From 4f693be33b1b58b32bb60131e8e4e01844d281f3 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 09:47:02 +0100 Subject: [PATCH 345/429] Move location creation to instance method on context --- .../Entities/Attribute.cs | 2 +- .../Entities/CommentBlock.cs | 4 +-- .../Entities/CommentLine.cs | 4 +-- .../Entities/Compilations/Diagnostic.cs | 2 +- .../Entities/Constructor.cs | 2 +- .../Entities/ExpressionNodeInfo.cs | 2 +- .../Entities/Expressions/Discard.cs | 2 +- .../Entities/Expressions/Initializer.cs | 2 +- .../Expressions/InterpolatedString.cs | 2 +- .../ObjectCreation/AnonymousObjectCreation.cs | 2 +- .../Expressions/Patterns/BinaryPattern.cs | 2 +- .../Entities/Expressions/Patterns/Pattern.cs | 4 +-- .../Expressions/Patterns/PositionalPattern.cs | 2 +- .../Expressions/Patterns/PropertyPattern.cs | 2 +- .../Expressions/Patterns/RecursivePattern.cs | 4 +-- .../Expressions/Patterns/RelationalPattern.cs | 2 +- .../Expressions/Patterns/UnaryPattern.cs | 2 +- .../Entities/Expressions/Query.cs | 6 ++-- .../Entities/Expressions/Switch.cs | 2 +- .../Expressions/VariableDeclaration.cs | 6 ++-- .../Entities/Field.cs | 4 +-- .../Entities/NamespaceDeclaration.cs | 4 +-- .../Entities/Parameter.cs | 2 +- .../PreprocessorDirective.cs | 2 +- .../Entities/Property.cs | 2 +- .../Entities/Statement`1.cs | 2 +- .../Entities/Statements/Case.cs | 2 +- .../Entities/Statements/Catch.cs | 2 +- .../Entities/Statements/Do.cs | 2 +- .../Entities/Statements/ForEach.cs | 2 +- .../Entities/Statements/LocalFunction.cs | 2 +- .../Entities/Symbol.cs | 4 +-- .../Entities/TypeMention.cs | 2 +- .../Entities/Types/NamedType.cs | 2 +- .../Entities/Types/TupleType.cs | 2 +- .../Entities/Types/TypeParameter.cs | 2 +- .../Entities/UsingDirective.cs | 4 +-- .../Populators/CompilationUnitVisitor.cs | 2 +- .../Populators/DirectiveVisitor.cs | 8 ++--- csharp/extractor/Semmle.Extraction/Context.cs | 34 ++++++++++++++----- .../Semmle.Extraction/Entities/Assembly.cs | 2 +- .../Entities/ExtractionError.cs | 2 +- .../Entities/GeneratedLocation.cs | 2 +- .../Semmle.Extraction/Entities/Location.cs | 26 -------------- .../Entities/SourceLocation.cs | 2 +- csharp/extractor/Semmle.Extraction/Message.cs | 4 +-- 46 files changed, 85 insertions(+), 95 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs index 9fef80b383a..e1663350055 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Attribute.cs @@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp.Entities private Semmle.Extraction.Entities.Location location; private Semmle.Extraction.Entities.Location Location => - location ?? (location = Semmle.Extraction.Entities.Location.Create(Context, attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation())); + location ?? (location = Context.CreateLocation(attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation())); public override bool NeedsPopulation => true; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs index ab6802cf457..9f105bb1e1a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentBlock.cs @@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.commentblock(this); var child = 0; - trapFile.commentblock_location(this, Context.Create(symbol.Location)); + trapFile.commentblock_location(this, Context.CreateLocation(symbol.Location)); foreach (var l in symbol.CommentLines) { trapFile.commentblock_child(this, (CommentLine)l, child++); @@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Context.Create(symbol.Location)); + trapFile.WriteSubId(Context.CreateLocation(symbol.Location)); trapFile.Write(";commentblock"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs index e390cb8c509..5ba3bbd87f4 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/CommentLine.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void Populate(TextWriter trapFile) { - location = Context.Create(Location); + location = Context.CreateLocation(Location); trapFile.commentline(this, Type == CommentLineType.MultilineContinuation ? CommentLineType.Multiline : Type, Text, RawText); trapFile.commentline_location(this, location); } @@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Context.Create(Location)); + trapFile.WriteSubId(Context.CreateLocation(Location)); trapFile.Write(";commentline"); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs index 2900e5b0ae0..ddf53d6bbe1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities protected override void Populate(TextWriter trapFile) { trapFile.diagnostics(this, (int)diagnostic.Severity, diagnostic.Id, diagnostic.Descriptor.Title.ToString(), - diagnostic.GetMessage(), Extraction.Entities.Location.Create(cx, diagnostic.Location)); + diagnostic.GetMessage(), cx.CreateLocation(diagnostic.Location)); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs index 499e6ec418a..0e4c2bbe9c0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Constructor.cs @@ -60,7 +60,7 @@ namespace Semmle.Extraction.CSharp.Entities var initInfo = new ExpressionInfo(Context, AnnotatedTypeSymbol.CreateNotAnnotated(initializerType), - Context.Create(initializer.ThisOrBaseKeyword.GetLocation()), + Context.CreateLocation(initializer.ThisOrBaseKeyword.GetLocation()), Kinds.ExprKind.CONSTRUCTOR_INIT, this, -1, diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs index febb84ded7c..6968ca65abb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs @@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp.Entities get { if (cachedLocation == null) - cachedLocation = Context.Create(CodeAnalysisLocation); + cachedLocation = Context.CreateLocation(CodeAnalysisLocation); return cachedLocation; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs index ef35f901b92..4f2eecca9da 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Discard.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions } private Discard(Context cx, CSharpSyntaxNode syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, cx.GetType(syntax), cx.Create(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) + base(new ExpressionInfo(cx, cx.GetType(syntax), cx.CreateLocation(syntax.GetLocation()), ExprKind.DISCARD, parent, child, false, null)) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index d96a44527d8..14fea3d4ce7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -137,7 +137,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var addMethod = Method.Create(cx, collectionInfo.Symbol as IMethodSymbol); var voidType = AnnotatedTypeSymbol.CreateNotAnnotated(cx.Compilation.GetSpecialType(SpecialType.System_Void)); - var invocation = new Expression(new ExpressionInfo(cx, voidType, cx.Create(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); + var invocation = new Expression(new ExpressionInfo(cx, voidType, cx.CreateLocation(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); if (addMethod != null) trapFile.expr_call(invocation, addMethod); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs index 152ff145897..836aae35beb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case SyntaxKind.InterpolatedStringText: // Create a string literal var interpolatedText = (InterpolatedStringTextSyntax)c; - new Expression(new ExpressionInfo(cx, Type, cx.Create(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text)); + new Expression(new ExpressionInfo(cx, Type, cx.CreateLocation(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text)); break; default: throw new InternalError(c, $"Unhandled interpolation kind {c.Kind()}"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs index 5703c3101a2..5a94a4333e8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs @@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var property = cx.GetModel(init).GetDeclaredSymbol(init); var propEntity = Property.Create(cx, property); var type = property.GetAnnotatedType(); - var loc = cx.Create(init.GetLocation()); + var loc = cx.CreateLocation(init.GetLocation()); var assignment = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null)); Create(cx, init.Expression, assignment, 0); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs index 33ea47d057b..2d0292ae720 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/BinaryPattern.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class BinaryPattern : Expression { public BinaryPattern(Context cx, BinaryPatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), GetKind(syntax.OperatorToken, syntax), parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), GetKind(syntax.OperatorToken, syntax), parent, child, false, null)) { Pattern.Create(cx, syntax.Left, this, 0); Pattern.Create(cx, syntax.Right, this, 1); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs index 65912ba12f1..05f3aab2526 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/Pattern.cs @@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (cx.GetModel(syntax).GetDeclaredSymbol(designation) is ILocalSymbol symbol) { var type = symbol.GetAnnotatedType(); - return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.Create(syntax.GetLocation()), false, parent, child); + return VariableDeclaration.Create(cx, symbol, type, declPattern.Type, cx.CreateLocation(syntax.GetLocation()), false, parent, child); } if (designation is DiscardDesignationSyntax) { @@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var type = symbol.GetAnnotatedType(); - return VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), true, parent, child); + return VariableDeclaration.Create(cx, symbol, type, null, cx.CreateLocation(syntax.GetLocation()), true, parent, child); } throw new InternalError(varPattern, "Unable to get the declared symbol of the var pattern designation."); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs index 0f3c2bf8800..f0ae03ae9dc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PositionalPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class PositionalPattern : Expression { internal PositionalPattern(Context cx, PositionalPatternClauseSyntax posPc, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(posPc.GetLocation()), ExprKind.POSITIONAL_PATTERN, parent, child, false, null)) { child = 0; foreach (var sub in posPc.Subpatterns) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs index ed947990045..7bd13e7a8a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/PropertyPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class PropertyPattern : Expression { internal PropertyPattern(Context cx, PropertyPatternClauseSyntax pp, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(pp.GetLocation()), ExprKind.PROPERTY_PATTERN, parent, child, false, null)) { child = 0; var trapFile = cx.TrapWriter.Writer; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs index 02246311648..d29292b3073 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RecursivePattern.cs @@ -16,7 +16,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions /// The parent pattern/expression. /// The child index of this pattern. public RecursivePattern(Context cx, RecursivePatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), ExprKind.RECURSIVE_PATTERN, parent, child, false, null)) { // Extract the type access if (syntax.Type is TypeSyntax t) @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { var type = symbol.GetAnnotatedType(); - VariableDeclaration.Create(cx, symbol, type, null, cx.Create(syntax.GetLocation()), false, this, 0); + VariableDeclaration.Create(cx, symbol, type, null, cx.CreateLocation(syntax.GetLocation()), false, this, 0); } if (syntax.PositionalPatternClause is PositionalPatternClauseSyntax posPc) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs index 77efd5668c4..c1a140005dc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/RelationalPattern.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class RelationalPattern : Expression { public RelationalPattern(Context cx, RelationalPatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), GetKind(syntax.OperatorToken), parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), GetKind(syntax.OperatorToken), parent, child, false, null)) { Expression.Create(cx, syntax.Expression, this, 0); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs index d80c390efff..ce2cf773a92 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Patterns/UnaryPattern.cs @@ -7,7 +7,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions internal class UnaryPattern : Expression { public UnaryPattern(Context cx, UnaryPatternSyntax syntax, IExpressionParentEntity parent, int child) : - base(new ExpressionInfo(cx, null, cx.Create(syntax.GetLocation()), ExprKind.NOT_PATTERN, parent, child, false, null)) + base(new ExpressionInfo(cx, null, cx.CreateLocation(syntax.GetLocation()), ExprKind.NOT_PATTERN, parent, child, false, null)) { Pattern.Create(cx, syntax.Pattern, this, 0); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs index 1db6c39fef2..f919aaca568 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Query.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { public QueryCall(Context cx, IMethodSymbol method, SyntaxNode clause, IExpressionParentEntity parent, int child) : base(new ExpressionInfo(cx, method?.GetAnnotatedReturnType(), - cx.Create(clause.GetLocation()), + cx.CreateLocation(clause.GetLocation()), ExprKind.METHOD_INVOCATION, parent, child, false, null)) { if (method != null) @@ -89,7 +89,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions variableSymbol, declType, declTypeSyntax, - cx.Create(node.GetLocation()), + cx.CreateLocation(node.GetLocation()), true, parent, child @@ -97,7 +97,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Expression.Create(cx, Expr, decl, 0); - var nameLoc = cx.Create(name.GetLocation()); + var nameLoc = cx.CreateLocation(name.GetLocation()); var access = new Expression(new ExpressionInfo(cx, type, nameLoc, ExprKind.LOCAL_VARIABLE_ACCESS, decl, 1, false, null)); cx.TrapWriter.Writer.expr_access(access, LocalVariable.Create(cx, variableSymbol)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs index 5fdc08c66d3..a6095ec63a2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { internal SwitchCase(Context cx, SwitchExpressionArmSyntax arm, Switch parent, int child) : base(new ExpressionInfo( - cx, cx.GetType(arm.Expression), cx.Create(arm.GetLocation()), + cx, cx.GetType(arm.Expression), cx.CreateLocation(arm.GetLocation()), ExprKind.SWITCH_CASE, parent, child, false, null)) { Expressions.Pattern.Create(cx, arm.Pattern, this, 0); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs index 349236e893a..674f45b3f21 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/VariableDeclaration.cs @@ -50,7 +50,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public static Expression CreateParenthesized(Context cx, DeclarationExpressionSyntax node, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { AnnotatedTypeSymbol? type = null; // Should ideally be a corresponding tuple type - var tuple = new Expression(new ExpressionInfo(cx, type, cx.Create(node.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); + var tuple = new Expression(new ExpressionInfo(cx, type, cx.CreateLocation(node.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); cx.Try(null, null, () => { @@ -65,7 +65,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public static Expression CreateParenthesized(Context cx, VarPatternSyntax varPattern, ParenthesizedVariableDesignationSyntax designation, IExpressionParentEntity parent, int child) { AnnotatedTypeSymbol? type = null; // Should ideally be a corresponding tuple type - var tuple = new Expression(new ExpressionInfo(cx, type, cx.Create(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); + var tuple = new Expression(new ExpressionInfo(cx, type, cx.CreateLocation(varPattern.GetLocation()), ExprKind.TUPLE, parent, child, false, null)); cx.Try(null, null, () => { @@ -123,7 +123,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions Create(cx, node, node.Designation, parent, child); public static VariableDeclaration Create(Context cx, CSharpSyntaxNode c, AnnotatedTypeSymbol? type, IExpressionParentEntity parent, int child) => - new VariableDeclaration(new ExpressionInfo(cx, type, cx.Create(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null)); + new VariableDeclaration(new ExpressionInfo(cx, type, cx.CreateLocation(c.FixedLocation()), ExprKind.LOCAL_VAR_DECL, parent, child, false, null)); public static VariableDeclaration Create(Context cx, CatchDeclarationSyntax d, bool isVar, IExpressionParentEntity parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs index aadd9d2fbab..d17b2f003aa 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Field.cs @@ -65,7 +65,7 @@ namespace Semmle.Extraction.CSharp.Entities { Context.PopulateLater(() => { - var loc = Context.Create(initializer.GetLocation()); + var loc = Context.CreateLocation(initializer.GetLocation()); var fieldAccess = AddInitializerAssignment(trapFile, initializer.Initializer.Value, loc, null, ref child); @@ -86,7 +86,7 @@ namespace Semmle.Extraction.CSharp.Entities ? Expression.ValueAsString(symbol.ConstantValue) : null; - var loc = Context.Create(initializer.GetLocation()); + var loc = Context.CreateLocation(initializer.GetLocation()); AddInitializerAssignment(trapFile, initializer.EqualsValue.Value, loc, constValue, ref child); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs index 17f9a198a39..3a19417008a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/NamespaceDeclaration.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(Context.Create(ReportingLocation)); + trapFile.WriteSubId(Context.CreateLocation(ReportingLocation)); trapFile.Write(";namespacedeclaration"); } @@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities var @namespace = (INamespaceSymbol)Context.GetModel(node).GetSymbolInfo(node.Name).Symbol; var ns = Namespace.Create(Context, @namespace); trapFile.namespace_declarations(this, ns); - trapFile.namespace_declaration_location(this, Context.Create(node.Name.GetLocation())); + trapFile.namespace_declaration_location(this, Context.CreateLocation(node.Name.GetLocation())); var visitor = new Populators.TypeOrNamespaceVisitor(Context, trapFile, this); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index c42a3edd236..325a77b6dd2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -110,7 +110,7 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, Parent, Original); foreach (var l in symbol.Locations) - trapFile.param_location(this, Context.Create(l)); + trapFile.param_location(this, Context.CreateLocation(l)); if (!IsSourceDeclaration || !symbol.FromSource()) return; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs index 6ea6172a2d3..4575dd8b8dc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities PopulatePreprocessor(trapFile); trapFile.preprocessor_directive_active(this, trivia.IsActive); - trapFile.preprocessor_directive_location(this, cx.Create(ReportingLocation)); + trapFile.preprocessor_directive_location(this, cx.CreateLocation(ReportingLocation)); if (!cx.Extractor.Standalone) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 08d5ae47c5e..6795c4a12df 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -84,7 +84,7 @@ namespace Semmle.Extraction.CSharp.Entities { Context.PopulateLater(() => { - var loc = Context.Create(initializer.GetLocation()); + var loc = Context.CreateLocation(initializer.GetLocation()); var annotatedType = AnnotatedTypeSymbol.CreateNotAnnotated(symbol.Type); var simpleAssignExpr = new Expression(new ExpressionInfo(Context, annotatedType, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, null)); Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Value, simpleAssignExpr, 0)); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs index 89b2b1696fd..1d8dd43f702 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs @@ -40,7 +40,7 @@ namespace Semmle.Extraction.CSharp.Entities protected abstract void PopulateStatement(TextWriter trapFile); protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child) - : this(cx, stmt, kind, parent, child, cx.Create(stmt.FixedLocation())) { } + : this(cx, stmt, kind, parent, child, cx.CreateLocation(stmt.FixedLocation())) { } public override string ToString() => Label.ToString(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs index e2a712c006b..8046bdb6e26 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements internal abstract class Case : Statement where TSyntax : SwitchLabelSyntax { protected Case(Context cx, TSyntax node, Switch parent, int child) - : base(cx, node, StmtKind.CASE, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.CASE, parent, child, cx.CreateLocation(node.GetLocation())) { } public static Statement Create(Context cx, SwitchLabelSyntax node, Switch parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs index db1a0d413c1..b9bddab82e2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements private static readonly string systemExceptionName = typeof(System.Exception).ToString(); private Catch(Context cx, CatchClauseSyntax node, Try parent, int child) - : base(cx, node, StmtKind.CATCH, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.CATCH, parent, child, cx.CreateLocation(node.GetLocation())) { } protected override void PopulateStatement(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs index a0cd9da7372..7cdcfb1f57b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements internal class Do : Statement { private Do(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) - : base(cx, node, StmtKind.DO, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.DO, parent, child, cx.CreateLocation(node.GetLocation())) { } public static Do Create(Context cx, DoStatementSyntax node, IStatementParentEntity parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 6696086b19c..4e4cce00926 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements var typeSymbol = semanticModel.GetDeclaredSymbol(Stmt); var type = typeSymbol.GetAnnotatedType(); - var location = cx.Create(Stmt.Identifier.GetLocation()); + var location = cx.CreateLocation(Stmt.Identifier.GetLocation()); Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs index eb81f27cb3a..5e417fd8885 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements internal class LocalFunction : Statement { private LocalFunction(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) - : base(cx, node, StmtKind.LOCAL_FUNCTION, parent, child, cx.Create(node.GetLocation())) { } + : base(cx, node, StmtKind.LOCAL_FUNCTION, parent, child, cx.CreateLocation(node.GetLocation())) { } public static LocalFunction Create(Context cx, LocalFunctionStatementSyntax node, IStatementParentEntity parent, int child) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs index 5e0850ba8c8..f7a493af78e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Symbol.cs @@ -78,7 +78,7 @@ namespace Semmle.Extraction.CSharp.Entities if (loc != null) { // Some built in operators lack locations, so loc is null. - yield return Context.Create(ReportingLocation); + yield return Context.CreateLocation(ReportingLocation); if (Context.Extractor.OutputPath != null && loc.Kind == LocationKind.SourceFile) yield return Assembly.CreateOutputAssembly(Context); } @@ -124,7 +124,7 @@ namespace Semmle.Extraction.CSharp.Entities public override bool NeedsPopulation => Context.Defines(symbol); - public Extraction.Entities.Location Location => Context.Create(ReportingLocation); + public Extraction.Entities.Location Location => Context.CreateLocation(ReportingLocation); protected void PopulateMetadataHandle(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs index 8d6074f3e8d..e05c2d0c102 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs @@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp.Entities private void Emit(TextWriter trapFile, Microsoft.CodeAnalysis.Location loc, IEntity parent, Type type) { trapFile.type_mention(this, type.TypeRef, parent); - trapFile.type_mention_location(this, cx.Create(loc)); + trapFile.type_mention_location(this, cx.CreateLocation(loc)); } public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs index bded5f60c57..0d95d776592 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/NamedType.cs @@ -106,7 +106,7 @@ namespace Semmle.Extraction.CSharp.Entities get { foreach (var l in GetLocations(symbol)) - yield return Context.Create(l); + yield return Context.CreateLocation(l); if (Context.Extractor.OutputPath != null && symbol.DeclaringSyntaxReferences.Any()) yield return Assembly.CreateOutputAssembly(Context); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs index 4ddc258f5c7..6f6ff85cf77 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TupleType.cs @@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities // about what locations are available for a tuple type. // Sometimes it's the source code, and sometimes it's empty. foreach (var l in symbol.Locations) - trapFile.type_location(this, Context.Create(l)); + trapFile.type_location(this, Context.CreateLocation(l)); } private readonly Lazy tupleElementsLazy; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index b4d35f7b506..e92a3891704 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -54,7 +54,7 @@ namespace Semmle.Extraction.CSharp.Entities foreach (var l in symbol.Locations) { - trapFile.type_location(this, Context.Create(l)); + trapFile.type_location(this, Context.CreateLocation(l)); } if (IsSourceDeclaration) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs index caa12ab0082..d08a1320ba2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs @@ -30,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Entities { var ns = Namespace.Create(cx, namespaceSymbol); trapFile.using_namespace_directives(this, ns); - trapFile.using_directive_location(this, cx.Create(ReportingLocation)); + trapFile.using_directive_location(this, cx.CreateLocation(ReportingLocation)); } else { @@ -44,7 +44,7 @@ namespace Semmle.Extraction.CSharp.Entities // A "using static" var m = Type.Create(cx, (ITypeSymbol)info.Symbol); trapFile.using_static_directives(this, m.TypeRef); - trapFile.using_directive_location(this, cx.Create(ReportingLocation)); + trapFile.using_directive_location(this, cx.CreateLocation(ReportingLocation)); } if (parent != null) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs index bebdee933cd..72f015464a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Populators public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) { // This information is not yet extracted. - cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Extraction.Entities.Location.Create(cx, node.GetLocation()), "", Severity.Info); + cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), cx.CreateLocation(node.GetLocation()), "", Severity.Info); } public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs index 9ec8d095290..0c400728554 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/DirectiveVisitor.cs @@ -67,7 +67,7 @@ namespace Semmle.Extraction.CSharp.Populators if (regionStarts.Count == 0) { cx.ExtractionError("Couldn't find start region", null, - Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); return; } @@ -100,7 +100,7 @@ namespace Semmle.Extraction.CSharp.Populators if (ifStarts.Count == 0) { cx.ExtractionError("Couldn't find start if", null, - Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); return; } @@ -113,7 +113,7 @@ namespace Semmle.Extraction.CSharp.Populators if (ifStarts.Count == 0) { cx.ExtractionError("Couldn't find start if", null, - Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); return; } @@ -126,7 +126,7 @@ namespace Semmle.Extraction.CSharp.Populators if (ifStarts.Count == 0) { cx.ExtractionError("Couldn't find start if", null, - Extraction.Entities.Location.Create(cx, node.GetLocation()), null, Util.Logging.Severity.Warning); + cx.CreateLocation(node.GetLocation()), null, Util.Logging.Severity.Warning); return; } diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 99e877f5ef2..7f5ef6b1110 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -77,7 +77,7 @@ namespace Semmle.Extraction { if (idLabelCache.ContainsKey(id)) { - this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), Entities.Location.Create(this, entity.ReportingLocation), "", Severity.Warning)); + this.Extractor.Message(new Message("Label collision for " + id, entity.Label.ToString(), CreateLocation(entity.ReportingLocation), "", Severity.Warning)); } else { @@ -211,11 +211,11 @@ namespace Semmle.Extraction } catch (InternalError ex) { - ExtractionError(new Message(ex.Text, ex.EntityText, Entities.Location.Create(this, ex.Location), ex.StackTrace)); + ExtractionError(new Message(ex.Text, ex.EntityText, CreateLocation(ex.Location), ex.StackTrace)); } catch (Exception ex) // lgtm[cs/catch-of-all-exceptions] { - ExtractionError($"Uncaught exception. {ex.Message}", null, Entities.Location.Create(this), ex.StackTrace); + ExtractionError($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace); } } } @@ -361,7 +361,7 @@ namespace Semmle.Extraction throw new InternalError("Unexpected TrapStackBehaviour"); } - var a = duplicationGuard && this.Create(entity.ReportingLocation) is NonGeneratedSourceLocation loc + var a = duplicationGuard && CreateLocation(entity.ReportingLocation) is NonGeneratedSourceLocation loc ? (Action)(() => WithDuplicationGuard(new Key(entity, loc), () => entity.Populate(TrapWriter.Writer))) : (Action)(() => this.Try(null, optionalSymbol, () => entity.Populate(TrapWriter.Writer))); @@ -436,15 +436,15 @@ namespace Semmle.Extraction { if (!(optionalSymbol is null)) { - ExtractionError(message, optionalSymbol.ToDisplayString(), Entities.Location.Create(this, optionalSymbol.Locations.FirstOrDefault())); + ExtractionError(message, optionalSymbol.ToDisplayString(), CreateLocation(optionalSymbol.Locations.FirstOrDefault())); } else if (!(optionalEntity is null)) { - ExtractionError(message, optionalEntity.Label.ToString(), Entities.Location.Create(this, optionalEntity.ReportingLocation)); + ExtractionError(message, optionalEntity.Label.ToString(), CreateLocation(optionalEntity.ReportingLocation)); } else { - ExtractionError(message, null, Entities.Location.Create(this)); + ExtractionError(message, null, CreateLocation()); } } @@ -517,11 +517,11 @@ namespace Semmle.Extraction } else if (ex is InternalError ie) { - message = new Message(ie.Text, ie.EntityText, Entities.Location.Create(this, ie.Location), ex.StackTrace); + message = new Message(ie.Text, ie.EntityText, CreateLocation(ie.Location), ex.StackTrace); } else { - message = new Message($"Uncaught exception. {ex.Message}", null, Entities.Location.Create(this), ex.StackTrace); + message = new Message($"Uncaught exception. {ex.Message}", null, CreateLocation(), ex.StackTrace); } ExtractionError(message); @@ -536,5 +536,21 @@ namespace Semmle.Extraction { TrapWriter.Emit(tuple); } + + public Entities.Location CreateLocation() + { + return SourceTree == null + ? GeneratedLocation.Create(this) + : CreateLocation(Microsoft.CodeAnalysis.Location.Create(SourceTree, Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(0, 0))); + } + + public Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location) + { + return (location == null || location.Kind == LocationKind.None) + ? GeneratedLocation.Create(this) + : location.IsInSource + ? NonGeneratedSourceLocation.Create(this, location) + : Assembly.Create(this, location); + } } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs index df3a5757618..e8b1e2cb46b 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs @@ -48,7 +48,7 @@ namespace Semmle.Extraction.Entities return false; } - public static new Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc); + public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc); private class AssemblyConstructorFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs index 3df0ce3bb61..96aabb57f8e 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/ExtractionError.cs @@ -15,7 +15,7 @@ namespace Semmle.Extraction.Entities protected override void Populate(TextWriter trapFile) { trapFile.extractor_messages(this, msg.Severity, "C# extractor", msg.Text, msg.EntityText ?? string.Empty, - msg.Location ?? Location.Create(cx), msg.StackTrace ?? string.Empty); + msg.Location ?? cx.CreateLocation(), msg.StackTrace ?? string.Empty); } public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; diff --git a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs index 31b5f55b0e6..6d05263aecd 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/GeneratedLocation.cs @@ -28,7 +28,7 @@ namespace Semmle.Extraction.Entities public override bool Equals(object? obj) => obj != null && obj.GetType() == typeof(GeneratedLocation); - public static new GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, typeof(GeneratedLocation), null); + public static GeneratedLocation Create(Context cx) => GeneratedLocationFactory.Instance.CreateEntity(cx, typeof(GeneratedLocation), null); private class GeneratedLocationFactory : ICachedEntityFactory { diff --git a/csharp/extractor/Semmle.Extraction/Entities/Location.cs b/csharp/extractor/Semmle.Extraction/Entities/Location.cs index b25436e9a41..cdd3c9a50dc 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Location.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Location.cs @@ -8,34 +8,8 @@ namespace Semmle.Extraction.Entities protected Location(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) { } - public static Location Create(Context cx, Microsoft.CodeAnalysis.Location? loc) => - (loc == null || loc.Kind == Microsoft.CodeAnalysis.LocationKind.None) - ? GeneratedLocation.Create(cx) - : loc.IsInSource - ? NonGeneratedSourceLocation.Create(cx, loc) - : Assembly.Create(cx, loc); - - public static Location Create(Context cx) - { - return cx.SourceTree == null - ? GeneratedLocation.Create(cx) - : Create(cx, Microsoft.CodeAnalysis.Location.Create(cx.SourceTree, TextSpan.FromBounds(0, 0))); - } - public override Microsoft.CodeAnalysis.Location? ReportingLocation => symbol; public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } - - public static class LocationExtensions - { - /// - /// Creates a Location entity. - /// - /// The extraction context. - /// The CodeAnalysis location. - /// The Location entity. - public static Location Create(this Context cx, Microsoft.CodeAnalysis.Location? location) => - Location.Create(cx, location); - } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs index e7bc4e3ea44..ae69f95449a 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.Entities FileEntity = File.Create(Context, Position.Path); } - public static new Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc); + public static Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => SourceLocationFactory.Instance.CreateEntity(cx, loc, loc); public override void Populate(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction/Message.cs index 0a2a62e13a2..a100a69a285 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction/Message.cs @@ -28,12 +28,12 @@ namespace Semmle.Extraction public static Message Create(Context cx, string text, ISymbol symbol, string? stackTrace = null, Severity severity = Severity.Error) { - return new Message(text, symbol.ToString(), Entities.Location.Create(cx, symbol.Locations.FirstOrDefault()), stackTrace, severity); + return new Message(text, symbol.ToString(), cx.CreateLocation(symbol.Locations.FirstOrDefault()), stackTrace, severity); } public static Message Create(Context cx, string text, SyntaxNode node, string? stackTrace = null, Severity severity = Severity.Error) { - return new Message(text, node.ToString(), Entities.Location.Create(cx, node.GetLocation()), stackTrace, severity); + return new Message(text, node.ToString(), cx.CreateLocation(node.GetLocation()), stackTrace, severity); } public override string ToString() => Text; From 6cc858b9ef5aeaff8b7cb991af0f24895255daa1 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 15 Feb 2021 09:19:18 +0100 Subject: [PATCH 346/429] Move AstLineCounter to top level class --- .../Entities/Method.AstLineCounter.cs | 51 ------------------- .../Entities/Method.cs | 2 +- .../Populators/AstLineCounter.cs | 48 +++++++++++++++++ 3 files changed, 49 insertions(+), 52 deletions(-) delete mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs deleted file mode 100644 index d567b6f6b56..00000000000 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.AstLineCounter.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Semmle.Util; -using System.IO; - -namespace Semmle.Extraction.CSharp.Entities -{ - public abstract partial class Method - { - private class AstLineCounter : CSharpSyntaxVisitor - { - public override LineCounts DefaultVisit(SyntaxNode node) - { - var text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); - return LineCounter.ComputeLineCounts(text); - } - - public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method) - { - return Visit(method.Identifier, method.Body ?? (SyntaxNode)method.ExpressionBody); - } - - public static LineCounts Visit(SyntaxToken identifier, SyntaxNode body) - { - var start = identifier.GetLocation().SourceSpan.Start; - var end = body.GetLocation().SourceSpan.End - 1; - - var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start); - - var text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; - return LineCounter.ComputeLineCounts(text); - } - - public override LineCounts VisitConstructorDeclaration(ConstructorDeclarationSyntax method) - { - return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); - } - - public override LineCounts VisitDestructorDeclaration(DestructorDeclarationSyntax method) - { - return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); - } - - public override LineCounts VisitOperatorDeclaration(OperatorDeclarationSyntax node) - { - return Visit(node.OperatorToken, node.Body ?? (SyntaxNode)node.ExpressionBody); - } - } - } -} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs index f036e373217..00bf8f3638e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Method.cs @@ -8,7 +8,7 @@ using System.Linq; namespace Semmle.Extraction.CSharp.Entities { - public abstract partial class Method : CachedSymbol, IExpressionParentEntity, IStatementParentEntity + public abstract class Method : CachedSymbol, IExpressionParentEntity, IStatementParentEntity { protected Method(Context cx, IMethodSymbol init) : base(cx, init) { } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs new file mode 100644 index 00000000000..a185675ee27 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/AstLineCounter.cs @@ -0,0 +1,48 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Semmle.Util; + +namespace Semmle.Extraction.CSharp.Populators +{ + internal class AstLineCounter : CSharpSyntaxVisitor + { + public override LineCounts DefaultVisit(SyntaxNode node) + { + var text = node.SyntaxTree.GetText().GetSubText(node.GetLocation().SourceSpan).ToString(); + return LineCounter.ComputeLineCounts(text); + } + + public override LineCounts VisitMethodDeclaration(MethodDeclarationSyntax method) + { + return Visit(method.Identifier, method.Body ?? (SyntaxNode)method.ExpressionBody); + } + + public static LineCounts Visit(SyntaxToken identifier, SyntaxNode body) + { + var start = identifier.GetLocation().SourceSpan.Start; + var end = body.GetLocation().SourceSpan.End - 1; + + var textSpan = new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start); + + var text = body.SyntaxTree.GetText().GetSubText(textSpan) + "\r\n"; + return LineCounter.ComputeLineCounts(text); + } + + public override LineCounts VisitConstructorDeclaration(ConstructorDeclarationSyntax method) + { + return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); + } + + public override LineCounts VisitDestructorDeclaration(DestructorDeclarationSyntax method) + { + return Visit(method.Identifier, (SyntaxNode)method.Body ?? method.ExpressionBody); + } + + public override LineCounts VisitOperatorDeclaration(OperatorDeclarationSyntax node) + { + return Visit(node.OperatorToken, node.Body ?? (SyntaxNode)node.ExpressionBody); + } + } + +} From 2de7fbe062e9371ef18262d167634fa2f29a44ff Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 15 Feb 2021 10:18:12 +0100 Subject: [PATCH 347/429] Fix build after rebase --- .../Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index 4e4cce00926..e7bb987574e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -45,7 +45,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements if (info.Equals(default)) { - cx.ExtractionError("Could not get foreach statement info", null, Location.Create(cx, this.ReportingLocation), severity: Util.Logging.Severity.Info); + cx.ExtractionError("Could not get foreach statement info", null, cx.CreateLocation(this.ReportingLocation), severity: Util.Logging.Severity.Info); return; } From c7072aef16559cbd1a366bb350b6f03553949742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Mon, 15 Feb 2021 10:34:20 +0100 Subject: [PATCH 348/429] update A.java test --- java/ql/test/query-tests/security/CWE-502/A.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 3b3de5f8ed2..d0a074d5900 100644 --- a/java/ql/test/query-tests/security/CWE-502/A.java +++ b/java/ql/test/query-tests/security/CWE-502/A.java @@ -88,10 +88,10 @@ public class A { public void deserializeSnakeYaml4(Socket sock) { Yaml yaml = new Yaml(new Constructor(A.class)); InputStream input = sock.getInputStream(); - Object o = yaml.load(input); //OK - Object o2 = yaml.loadAll(input); //OK - Object o3 = yaml.parse(new InputStreamReader(input)); //OK - A o4 = yaml.loadAs(input, A.class); //OK - A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //OK + Object o = yaml.load(input); //unsafe + Object o2 = yaml.loadAll(input); //unsafe + Object o3 = yaml.parse(new InputStreamReader(input)); //unsafe + A o4 = yaml.loadAs(input, A.class); //unsafe + A o5 = yaml.loadAs(new InputStreamReader(input), A.class); //unsafe } } From 504d119749143302ff45e6583928a8aad82ae489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Mon, 15 Feb 2021 10:58:17 +0100 Subject: [PATCH 349/429] adjust max parameter number --- java/ql/src/semmle/code/java/frameworks/apache/Lang.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index c9af49464e0..2e124235bb7 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -45,7 +45,7 @@ private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingC override predicate returnsTaintFrom(int src) { this.hasName(["addAll", "addFirst"]) and - src = [0 .. getNumberOfParameters()] + src = [0 .. getNumberOfParameters() - 1] or this.hasName([ "clone", "nullToEmpty", "remove", "removeAll", "removeElement", "removeElements", "reverse", From 00a0b12dad114993342306163e0f1d98fc6a82f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Mon, 15 Feb 2021 11:23:40 +0100 Subject: [PATCH 350/429] update expected results --- .../CWE-502/UnsafeDeserialization.expected | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected index 672a692c03f..f575a093d6e 100644 --- a/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected +++ b/java/ql/test/query-tests/security/CWE-502/UnsafeDeserialization.expected @@ -16,6 +16,11 @@ edges | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) | | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input | | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:91:26:91:30 | input | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:92:30:92:34 | input | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:93:28:93:55 | new InputStreamReader(...) | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:94:24:94:28 | input | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:95:24:95:51 | new InputStreamReader(...) | | B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream | | B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes | | B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s | @@ -46,6 +51,12 @@ nodes | A.java:73:28:73:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | | A.java:74:24:74:28 | input | semmle.label | input | | A.java:75:24:75:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | +| A.java:90:25:90:45 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| A.java:91:26:91:30 | input | semmle.label | input | +| A.java:92:30:92:34 | input | semmle.label | input | +| A.java:93:28:93:55 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | +| A.java:94:24:94:28 | input | semmle.label | input | +| A.java:95:24:95:51 | new InputStreamReader(...) | semmle.label | new InputStreamReader(...) | | B.java:7:31:7:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | B.java:8:29:8:39 | inputStream | semmle.label | inputStream | | B.java:12:31:12:51 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | @@ -74,6 +85,11 @@ nodes | A.java:73:17:73:56 | parse(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:73:28:73:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | | A.java:74:12:74:38 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:74:24:74:28 | input | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | | A.java:75:12:75:61 | loadAs(...) | A.java:70:25:70:45 | getInputStream(...) : InputStream | A.java:75:24:75:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:70:25:70:45 | getInputStream(...) | user input | +| A.java:91:16:91:31 | load(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:91:26:91:30 | input | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input | +| A.java:92:17:92:35 | loadAll(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:92:30:92:34 | input | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input | +| A.java:93:17:93:56 | parse(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:93:28:93:55 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input | +| A.java:94:12:94:38 | loadAs(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:94:24:94:28 | input | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input | +| A.java:95:12:95:61 | loadAs(...) | A.java:90:25:90:45 | getInputStream(...) : InputStream | A.java:95:24:95:51 | new InputStreamReader(...) | Unsafe deserialization of $@. | A.java:90:25:90:45 | getInputStream(...) | user input | | B.java:8:12:8:46 | parseObject(...) | B.java:7:31:7:51 | getInputStream(...) : InputStream | B.java:8:29:8:39 | inputStream | Unsafe deserialization of $@. | B.java:7:31:7:51 | getInputStream(...) | user input | | B.java:15:12:15:28 | parse(...) | B.java:12:31:12:51 | getInputStream(...) : InputStream | B.java:15:23:15:27 | bytes | Unsafe deserialization of $@. | B.java:12:31:12:51 | getInputStream(...) | user input | | B.java:23:12:23:30 | parseObject(...) | B.java:19:31:19:51 | getInputStream(...) : InputStream | B.java:23:29:23:29 | s | Unsafe deserialization of $@. | B.java:19:31:19:51 | getInputStream(...) | user input | From f79b3144e3478a3d65cbf548b7a0d9446dfdd2bd Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 11:31:31 +0100 Subject: [PATCH 351/429] C++: Refactor IdentityFunction.qll. --- .../code/cpp/models/implementations/IdentityFunction.qll | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll index bd188cffe49..60afd2b25ef 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/IdentityFunction.qll @@ -6,12 +6,9 @@ import semmle.code.cpp.models.interfaces.SideEffect /** * The standard function templates `std::move` and `std::forward`. */ -private class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction { - IdentityFunction() { - this.getNamespace().getParentNamespace() instanceof GlobalNamespace and - this.getNamespace().getName() = "std" and - this.getName() = ["move", "forward"] - } +private class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFunction, + FunctionTemplateInstantiation { + IdentityFunction() { this.hasQualifiedName("std", ["move", "forward"]) } override predicate hasOnlySpecificReadSideEffects() { any() } From e5db0ef16bbd4f128af86e2e7ab5d726abb3489c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 15 Feb 2021 11:58:26 +0100 Subject: [PATCH 352/429] remove the `RequestExpr` requirement from `FormParsers.qll`, and use API graphs. --- .../javascript/frameworks/FormParsers.qll | 78 +++++++------------ 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll index e8f9b76a40e..73e00a8e96f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/FormParsers.qll @@ -5,28 +5,20 @@ import javascript /** - * Classes and predicate modelling the `Busboy` library. + * A source of remote flow from the `Busboy` library. */ -private module Busboy { - /** - * A `Busboy` instance that has request data flowing into it. - */ - private DataFlow::NewNode busboy() { - result = DataFlow::moduleImport("busboy").getAnInstantiation() and - exists(MethodCallExpr pipe | - pipe.calls(any(HTTP::RequestExpr req), "pipe") and - result.flowsToExpr(pipe.getArgument(0)) - ) +private class BusBoyRemoteFlow extends RemoteFlowSource { + BusBoyRemoteFlow() { + this = + API::moduleImport("busboy") + .getInstance() + .getMember("on") + .getParameter(1) + .getAParameter() + .getAnImmediateUse() } - /** - * A source of remote flow from the `Busboy` library. - */ - class BusBoyRemoteFlow extends RemoteFlowSource { - BusBoyRemoteFlow() { this = busboy().getAMemberCall("on").getABoundCallbackParameter(1, _) } - - override string getSourceType() { result = "parsed user value from Busbuy" } - } + override string getSourceType() { result = "parsed user value from Busbuy" } } /** @@ -34,17 +26,16 @@ private module Busboy { */ private class FormidableRemoteFlow extends RemoteFlowSource { FormidableRemoteFlow() { - exists(DataFlow::CallNode parse, DataFlow::InvokeNode formidable | - formidable = DataFlow::moduleImport("formidable").getACall() + exists(API::Node formidable | + formidable = API::moduleImport("formidable").getReturn() or - formidable = DataFlow::moduleMember("formidable", "formidable").getACall() + formidable = API::moduleImport("formidable").getMember("formidable").getReturn() or formidable = - DataFlow::moduleMember("formidable", ["IncomingForm", "Formidable"]).getAnInstantiation() + API::moduleImport("formidable").getMember(["IncomingForm", "Formidable"]).getInstance() | - parse = formidable.getAMemberCall("parse") and - parse.getArgument(0).asExpr() instanceof HTTP::RequestExpr and - this = parse.getABoundCallbackParameter(1, any(int i | i > 0)) + this = + formidable.getMember("parse").getACall().getABoundCallbackParameter(1, any(int i | i > 0)) ) } @@ -52,34 +43,21 @@ private class FormidableRemoteFlow extends RemoteFlowSource { } /** - * Predicates and classes modelling the `multiparty` library. + * A source of remote flow from the `Multiparty` library. */ -private module Multiparty { - /** - * Gets an instance of of `Multiparty` form parser that parses a HTTP request object. - * The `parse` call is the method call that receives the HTTP request object. - */ - private DataFlow::SourceNode form(DataFlow::MethodCallNode parse) { - result = DataFlow::moduleMember("multiparty", "Form").getAnInstantiation() and - parse = result.getAMethodCall("parse") and - parse.getArgument(0).asExpr() instanceof HTTP::RequestExpr - } - - /** - * A source of remote flow from the `Multiparty` library. - */ - class MultipartyRemoteFlow extends RemoteFlowSource { - MultipartyRemoteFlow() { - exists(DataFlow::MethodCallNode parse | exists(form(parse)) | - this = parse.getABoundCallbackParameter(1, any(int i | i > 0)) +private class MultipartyRemoteFlow extends RemoteFlowSource { + MultipartyRemoteFlow() { + exists(API::Node form | form = API::moduleImport("multiparty").getMember("Form").getInstance() | + exists(API::CallNode parse | parse = form.getMember("parse").getACall() | + this = parse.getParameter(1).getAParameter().getAnImmediateUse() ) or - exists(DataFlow::MethodCallNode on | on = form(_).getAMethodCall("on") | + exists(API::CallNode on | on = form.getMember("on").getACall() | on.getArgument(0).mayHaveStringValue(["part", "file", "field"]) and - this = on.getABoundCallbackParameter(1, _) + this = on.getParameter(1).getAParameter().getAnImmediateUse() ) - } - - override string getSourceType() { result = "parsed user value from Multiparty" } + ) } + + override string getSourceType() { result = "parsed user value from Multiparty" } } From 0f9b044814edf7fe30fafe7044755466e354d92b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 15 Feb 2021 12:04:51 +0100 Subject: [PATCH 353/429] C++: Model vector versions of BSD-style reads and writes. --- .../code/cpp/models/implementations/Recv.qll | 5 +++- .../code/cpp/models/implementations/Send.qll | 5 +++- .../defaulttainttracking.cpp | 28 +++++++++++++++++-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll index ef919c9eb39..691ba528f42 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Recv.qll @@ -18,7 +18,10 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction, "recvfrom", // recvfrom(socket, dest, len, flags, from, fromlen) "recvmsg", // recvmsg(socket, msg, flags) "read", // read(socket, dest, len) - "pread" // pread(socket, dest, len, offset) + "pread", // pread(socket, dest, len, offset) + "readv", // readv(socket, dest, len) + "preadv", // readv(socket, dest, len, offset) + "preadv2" // readv2(socket, dest, len, offset, flags) ]) } diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll index 2a6cd0bac51..6086bc7748f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Send.qll @@ -16,7 +16,10 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem "send", // send(socket, buf, len, flags) "sendto", // sendto(socket, buf, len, flags, to, tolen) "sendmsg", // sendmsg(socket, msg, flags) - "write" // write(socket, buf, len); + "write", // write(socket, buf, len) + "writev", // writev(socket, buf, len) + "pwritev", // pwritev(socket, buf, len, offset) + "pwritev2" // pwritev2(socket, buf, len, offset, flags) ]) } diff --git a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp index 6156e80015c..020a2f90b9e 100644 --- a/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp +++ b/cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_sinks_only/defaulttainttracking.cpp @@ -228,10 +228,34 @@ void test_recv() { sink(*buffer); // $ ast,ir } -// --- send --- +// --- send and related functions --- int send(int, const void*, int, int); void test_send(char* buffer, int length) { send(0, buffer, length, 0); // $ remote -} \ No newline at end of file +} + +struct iovec { + void *iov_base; + unsigned iov_len; +}; + +int readv(int, const struct iovec*, int); +int writev(int, const struct iovec*, int); + +void sink(const iovec* iovs); +void sink(iovec); + +int test_readv_and_writev(iovec* iovs) { + readv(0, iovs, 16); + sink(iovs); // $ast,ir + sink(iovs[0]); // $ast MISSING: ir + sink(*iovs); // $ast MISSING: ir + + char* p = (char*)iovs[1].iov_base; + sink(p); // $ MISSING: ast,ir + sink(*p); // $ MISSING: ast,ir + + writev(0, iovs, 16); // $ remote +} From a9071a62a0c77f1e046f144073ae361c4f5748d4 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 12:15:17 +0100 Subject: [PATCH 354/429] C++: Refactor Memcpy.qll and include bsl model. --- cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 02fa810142f..25229279db1 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -20,7 +20,7 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect // memcpy(dest, src, num) // memmove(dest, src, num) // memmove(dest, src, num, remaining) - this.hasGlobalOrStdName(["memcpy", "memmove"]) + this.hasQualifiedName(["", "std", "bsl"], ["memcpy", "memmove"]) or // bcopy(src, dest, num) // mempcpy(dest, src, num) From 74ce7369f8d5ea5b4f1be2e112d32da18ba64391 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 15 Feb 2021 12:35:16 +0100 Subject: [PATCH 355/429] Update javascript/change-notes/2021-02-09-form-parsers.md Co-authored-by: Asger F --- javascript/change-notes/2021-02-09-form-parsers.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/javascript/change-notes/2021-02-09-form-parsers.md b/javascript/change-notes/2021-02-09-form-parsers.md index 4ad87cff32b..ec45a6c144d 100644 --- a/javascript/change-notes/2021-02-09-form-parsers.md +++ b/javascript/change-notes/2021-02-09-form-parsers.md @@ -1,6 +1,7 @@ lgtm,codescanning * Server side form parsing libraries are now recognized as source of remote user input. - [multer](https://www.npmjs.com/package/multer) and - [busboy](https://www.npmjs.com/package/busboy) and - [formidable](https://www.npmjs.com/package/formidable) and - [multiparty](https://www.npmjs.com/package/formidable) \ No newline at end of file + Affected packages are + [multer](https://www.npmjs.com/package/multer), + [busboy](https://www.npmjs.com/package/busboy), + [formidable](https://www.npmjs.com/package/formidable), and + [multiparty](https://www.npmjs.com/package/formidable). From 2a3d20d9a94a9abc835fd98c5aa0f88478b1c51a Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 12:36:18 +0100 Subject: [PATCH 356/429] C++: Refactor Memset.qll and include bsl model. --- cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 6636b34fe9d..7d6a470589d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -15,7 +15,9 @@ import semmle.code.cpp.models.interfaces.SideEffect private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction, SideEffectFunction { MemsetFunction() { - this.hasGlobalOrStdName(["memset", "wmemset"]) + this.hasQualifiedName(["", "std", "bsl"], "memset") + or + this.hasGlobalOrStdName("wmemset") or this.hasGlobalName([bzero(), "__builtin_memset", "__builtin_memset_chk"]) } From da38377e365b8f50fa2c9a77a6b112e961e0bff8 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 12:12:29 +0000 Subject: [PATCH 357/429] C++: Simplify code. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 13 +++++++++++++ .../code/cpp/models/implementations/Memcpy.qll | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 35ae092780d..1f488bfeb5f 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -139,6 +139,19 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName("std", "", name) } + /** + * Holds if this declaration has the given name in the global namespace, + * the `std` namespace or the `bsl` namespace. + * We treat `std` and `bsl` as the same in a bunch of our models. + */ + predicate hasGlobalOrStdishName(string name) { + this.hasGlobalName(name) + or + this.hasQualifiedName("std", "", name) + or + this.hasQualifiedName("bsl", "", name) + } + /** Gets a specifier of this declaration. */ Specifier getASpecifier() { none() } // overridden in subclasses diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll index 25229279db1..3b02ba58e11 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memcpy.qll @@ -20,7 +20,7 @@ private class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffect // memcpy(dest, src, num) // memmove(dest, src, num) // memmove(dest, src, num, remaining) - this.hasQualifiedName(["", "std", "bsl"], ["memcpy", "memmove"]) + this.hasGlobalOrStdishName(["memcpy", "memmove"]) or // bcopy(src, dest, num) // mempcpy(dest, src, num) From 79e3bf80c3e639e795269f1fc179c4e7474afde3 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 12:13:25 +0000 Subject: [PATCH 358/429] C++: Simplify code. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 13 +++++++++++++ .../code/cpp/models/implementations/Memset.qll | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 35ae092780d..1f488bfeb5f 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -139,6 +139,19 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName("std", "", name) } + /** + * Holds if this declaration has the given name in the global namespace, + * the `std` namespace or the `bsl` namespace. + * We treat `std` and `bsl` as the same in a bunch of our models. + */ + predicate hasGlobalOrStdishName(string name) { + this.hasGlobalName(name) + or + this.hasQualifiedName("std", "", name) + or + this.hasQualifiedName("bsl", "", name) + } + /** Gets a specifier of this declaration. */ Specifier getASpecifier() { none() } // overridden in subclasses diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 7d6a470589d..5e3f446713f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.SideEffect private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction, SideEffectFunction { MemsetFunction() { - this.hasQualifiedName(["", "std", "bsl"], "memset") + this.hasGlobalOrStdishName("memset") or this.hasGlobalOrStdName("wmemset") or From c9af97b742ccc9bc544896a7266743eaa2479f77 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 12:30:31 +0000 Subject: [PATCH 359/429] C++: Model bsl functions in Pure.qll. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 13 +++++++++++++ .../semmle/code/cpp/models/implementations/Pure.qll | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 35ae092780d..1f488bfeb5f 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -139,6 +139,19 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName("std", "", name) } + /** + * Holds if this declaration has the given name in the global namespace, + * the `std` namespace or the `bsl` namespace. + * We treat `std` and `bsl` as the same in a bunch of our models. + */ + predicate hasGlobalOrStdishName(string name) { + this.hasGlobalName(name) + or + this.hasQualifiedName("std", "", name) + or + this.hasQualifiedName("bsl", "", name) + } + /** Gets a specifier of this declaration. */ Specifier getASpecifier() { none() } // overridden in subclasses diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index 0dfa7fe6d76..4682032f284 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.SideEffect private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureStrFunction() { - hasGlobalOrStdName([ + hasGlobalOrStdishName([ atoi(), "strcasestr", "strchnul", "strchr", "strchrnul", "strstr", "strpbrk", "strrchr", "strspn", strtol(), strrev(), strcmp(), strlwr(), strupr() ]) @@ -92,7 +92,7 @@ private string strcmp() { /** String standard `strlen` function, and related functions for computing string lengths. */ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { StrLenFunction() { - hasGlobalOrStdName(["strlen", "strnlen", "wcslen"]) + hasGlobalOrStdishName(["strlen", "strnlen", "wcslen"]) or hasGlobalName(["_mbslen", "_mbslen_l", "_mbstrlen", "_mbstrlen_l"]) } @@ -125,7 +125,7 @@ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFun /** Pure functions. */ private class PureFunction extends TaintFunction, SideEffectFunction { - PureFunction() { hasGlobalOrStdName(["abs", "labs"]) } + PureFunction() { hasGlobalOrStdishName(["abs", "labs"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { exists(ParameterIndex i | @@ -144,7 +144,7 @@ private class PureFunction extends TaintFunction, SideEffectFunction { private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureMemFunction() { - hasGlobalOrStdName([ + hasGlobalOrStdishName([ "memchr", "__builtin_memchr", "memrchr", "rawmemchr", "memcmp", "__builtin_memcmp", "memmem" ]) or this.hasGlobalName("memfrob") From 27c479a8baf6103ccb0ae2182292973c45b26251 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Mon, 15 Feb 2021 13:51:29 +0100 Subject: [PATCH 360/429] Python: Limit `RequestInputAccess` to immediate uses This fixes some spurious results that occurred when we considered _any_ use of `request.something` to be a source, even ones we had tracked into other functions. To prevent this, using `getAnImmediateUse` better captures the fact that we want the source to be just the actual attribute access. --- python/ql/src/semmle/python/frameworks/Flask.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index c0702ab7391..fe394c6c8ac 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -312,7 +312,7 @@ private module FlaskModel { RequestInputAccess() { // attributes - this = flask::request().getMember(attr_name).getAUse() and + this = flask::request().getMember(attr_name).getAnImmediateUse() and attr_name in [ // str "path", "full_path", "base_url", "url", "access_control_request_method", From 2ca12aa6125a84436938d82bda3d8baf1d9a1d67 Mon Sep 17 00:00:00 2001 From: Taus Date: Mon, 15 Feb 2021 14:21:12 +0100 Subject: [PATCH 361/429] Update python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll Co-authored-by: Rasmus Wriedt Larsen --- .../src/semmle/python/dataflow/new/internal/DataFlowPublic.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll index b86bdd2a3cf..3d844047327 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll @@ -175,7 +175,7 @@ class CallCfgNode extends CfgNode { */ Node getFunction() { result.asCfgNode() = node.getFunction() } - /** Gets the data-flow node corresponding to the nth argument of the call corresponding to this data-flow node */ + /** Gets the data-flow node corresponding to the i'th argument of the call corresponding to this data-flow node */ Node getArg(int i) { result.asCfgNode() = node.getArg(i) } /** Gets the data-flow node corresponding to the named argument of the call corresponding to this data-flow node */ From 923e1c5e9ba9232586a8d0156a56a526be27dfc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Mon, 15 Feb 2021 14:41:18 +0100 Subject: [PATCH 362/429] add change note for new ArrayUtils support --- java/change-notes/2021-02-15-commons-array-utils.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 java/change-notes/2021-02-15-commons-array-utils.md diff --git a/java/change-notes/2021-02-15-commons-array-utils.md b/java/change-notes/2021-02-15-commons-array-utils.md new file mode 100644 index 00000000000..a689a08e98c --- /dev/null +++ b/java/change-notes/2021-02-15-commons-array-utils.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added support for the Apache Commons Lang ArrayUtils library. From 3d3f4ba797675f9a3bebe767148a47824578e286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mun=CC=83oz?= Date: Mon, 15 Feb 2021 14:53:16 +0100 Subject: [PATCH 363/429] add change note --- java/change-notes/2021-02-15-snakeyaml-fn-fix.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 java/change-notes/2021-02-15-snakeyaml-fn-fix.md diff --git a/java/change-notes/2021-02-15-snakeyaml-fn-fix.md b/java/change-notes/2021-02-15-snakeyaml-fn-fix.md new file mode 100644 index 00000000000..ed08bdfe8c6 --- /dev/null +++ b/java/change-notes/2021-02-15-snakeyaml-fn-fix.md @@ -0,0 +1,5 @@ +lgtm,codescanning +* The query "Unsafe Deserialization" (`java/unsafe-deserialization`) has been + improved to report those cases where SnakeYaml `Constructor` is used to fix + the unmarshaled object graph root's type but injection is still possible in + nested nodes of the object graph. From 3afe934a05c694412215be4be80c546169fb9d5d Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 15:40:17 +0000 Subject: [PATCH 364/429] C++: Model bsl functions in Swap.qll. --- cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll index 285d20b8660..b79f7afe5d9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Swap.qll @@ -9,7 +9,7 @@ import semmle.code.cpp.models.interfaces.Alias * ``` */ private class Swap extends DataFlowFunction { - Swap() { this.hasQualifiedName("std", "swap") } + Swap() { this.hasQualifiedName(["std", "bsl"], "swap") } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { input.isParameterDeref(0) and From 9d19752d9a9dfd89ac21f5b7337d3de94226cb40 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 15:42:34 +0000 Subject: [PATCH 365/429] C++: Model bsl functions in Strcat.qll. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 13 +++++++++++++ .../code/cpp/models/implementations/Strcat.qll | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 35ae092780d..1f488bfeb5f 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -139,6 +139,19 @@ class Declaration extends Locatable, @declaration { this.hasQualifiedName("std", "", name) } + /** + * Holds if this declaration has the given name in the global namespace, + * the `std` namespace or the `bsl` namespace. + * We treat `std` and `bsl` as the same in a bunch of our models. + */ + predicate hasGlobalOrStdishName(string name) { + this.hasGlobalName(name) + or + this.hasQualifiedName("std", "", name) + or + this.hasQualifiedName("bsl", "", name) + } + /** Gets a specifier of this declaration. */ Specifier getASpecifier() { none() } // overridden in subclasses diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index f31d688d010..6dbed650cfa 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction { StrcatFunction() { - this.hasGlobalOrStdName([ + this.hasGlobalOrStdishName([ "strcat", // strcat(dst, src) "strncat", // strncat(dst, src, max_amount) "wcscat", // wcscat(dst, src) From fd91a972a596f36761eabca1836156685afc7183 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 15:43:31 +0000 Subject: [PATCH 366/429] C++: Model bsl functions in Strcpy.qll. --- cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index e01d364c5a7..72f993b7a4a 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction { StrcpyFunction() { - this.hasGlobalOrStdName([ + this.hasGlobalOrStdishName([ "strcpy", // strcpy(dst, src) "wcscpy", // wcscpy(dst, src) "strncpy", // strncpy(dst, src, max_amount) From fd2e0292c31533758219180dfa3ffb2b14de1255 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 16:00:37 +0000 Subject: [PATCH 367/429] C++: Model bsl functions in Strtok.qll. --- cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll index 659494ef2dd..3b7e97a53d0 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.Taint */ private class Strtok extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction { Strtok() { - this.hasGlobalOrStdName("strtok") or + this.hasGlobalOrStdishName("strtok") or this.hasGlobalName(["strtok_r", "_strtok_l", "wcstok", "_wcstok_l", "_mbstok", "_mbstok_l"]) } From ba6e6337f3e002105f4b3288afa6246caf998d8d Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Mon, 15 Feb 2021 16:08:03 +0000 Subject: [PATCH 368/429] C++: Fix TopLevelFunction's qldoc --- cpp/ql/src/semmle/code/cpp/Function.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/Function.qll b/cpp/ql/src/semmle/code/cpp/Function.qll index 4ddf852f49f..ac345e8a29a 100644 --- a/cpp/ql/src/semmle/code/cpp/Function.qll +++ b/cpp/ql/src/semmle/code/cpp/Function.qll @@ -680,7 +680,7 @@ class FunctionDeclarationEntry extends DeclarationEntry, @fun_decl { /** * A C/C++ non-member function (a function that is not a member of any - * class). For example the in the following code, `MyFunction` is a + * class). For example, in the following code, `MyFunction` is a * `TopLevelFunction` but `MyMemberFunction` is not: * ``` * void MyFunction() { From b670e5b04bba0f83897201922d371cdcd8a43b71 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 16:12:35 +0000 Subject: [PATCH 369/429] C++: Model bsl functions in Printf.qll. --- .../cpp/models/implementations/Printf.qll | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index 1767261efac..f70493e9f83 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -15,7 +15,7 @@ private class Printf extends FormattingFunction, AliasFunction { Printf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName(["printf", "wprintf"]) or + hasGlobalOrStdishName(["printf", "wprintf"]) or hasGlobalName(["printf_s", "wprintf_s", "g_printf"]) ) and not exists(getDefinition().getFile().getRelativePath()) @@ -23,10 +23,7 @@ private class Printf extends FormattingFunction, AliasFunction { override int getFormatParameterIndex() { result = 0 } - deprecated override predicate isWideCharDefault() { - hasGlobalOrStdName("wprintf") or - hasGlobalName("wprintf_s") - } + deprecated override predicate isWideCharDefault() { hasName(["wprintf", "wprintf_s"]) } override predicate isOutputGlobal() { any() } @@ -44,7 +41,7 @@ private class Fprintf extends FormattingFunction { Fprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName(["fprintf", "fwprintf"]) or + hasGlobalOrStdishName(["fprintf", "fwprintf"]) or hasGlobalName("g_fprintf") ) and not exists(getDefinition().getFile().getRelativePath()) @@ -52,7 +49,7 @@ private class Fprintf extends FormattingFunction { override int getFormatParameterIndex() { result = 1 } - deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") } + deprecated override predicate isWideCharDefault() { hasName("fwprintf") } override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = true } } @@ -64,7 +61,7 @@ private class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName([ + hasGlobalOrStdishName([ "sprintf", // sprintf(dst, format, args...) "wsprintf" // wsprintf(dst, format, args...) ]) @@ -90,22 +87,20 @@ private class Sprintf extends FormattingFunction { } override int getFormatParameterIndex() { - hasGlobalName("g_strdup_printf") and result = 0 + hasName("g_strdup_printf") and result = 0 or - hasGlobalName("__builtin___sprintf_chk") and result = 3 + hasName("__builtin___sprintf_chk") and result = 3 or not getName() = ["g_strdup_printf", "__builtin___sprintf_chk"] and result = 1 } override int getOutputParameterIndex(boolean isStream) { - not hasGlobalName("g_strdup_printf") and result = 0 and isStream = false + not hasName("g_strdup_printf") and result = 0 and isStream = false } override int getFirstFormatArgumentIndex() { - if hasGlobalName("__builtin___sprintf_chk") - then result = 4 - else result = getNumberOfParameters() + if hasName("__builtin___sprintf_chk") then result = 4 else result = getNumberOfParameters() } } @@ -116,7 +111,7 @@ private class SnprintfImpl extends Snprintf { SnprintfImpl() { this instanceof TopLevelFunction and ( - hasGlobalOrStdName([ + hasGlobalOrStdishName([ "snprintf", // C99 defines snprintf "swprintf" // The s version of wide-char printf is also always the n version ]) @@ -163,10 +158,7 @@ private class SnprintfImpl extends Snprintf { } override predicate returnsFullFormatLength() { - ( - hasGlobalOrStdName("snprintf") or - hasGlobalName(["g_snprintf", "__builtin___snprintf_chk", "snprintf_s"]) - ) and + hasName(["snprintf", "g_snprintf", "__builtin___snprintf_chk", "snprintf_s"]) and not exists(getDefinition().getFile().getRelativePath()) } From d9c6f7bc3564956be9d72f4470920971726b66eb Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 16:12:46 +0000 Subject: [PATCH 370/429] C++: Model bsl functions in Scanf.qll. --- cpp/ql/src/semmle/code/cpp/commons/Scanf.qll | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll b/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll index 4b75bbe27d2..aec047cea6b 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll @@ -34,10 +34,10 @@ class Scanf extends ScanfFunction { Scanf() { this instanceof TopLevelFunction and ( - hasName("scanf") or // scanf(format, args...) - hasName("wscanf") or // wscanf(format, args...) - hasName("_scanf_l") or // _scanf_l(format, locale, args...) - hasName("_wscanf_l") // _wscanf_l(format, locale, args...) + hasGlobalOrStdishName("scanf") or // scanf(format, args...) + hasGlobalOrStdishName("wscanf") or // wscanf(format, args...) + hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...) + hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...) ) } @@ -53,10 +53,10 @@ class Fscanf extends ScanfFunction { Fscanf() { this instanceof TopLevelFunction and ( - hasName("fscanf") or // fscanf(src_stream, format, args...) - hasName("fwscanf") or // fwscanf(src_stream, format, args...) - hasName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) - hasName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) + hasGlobalOrStdishName("fscanf") or // fscanf(src_stream, format, args...) + hasGlobalOrStdishName("fwscanf") or // fwscanf(src_stream, format, args...) + hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) + hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) ) } @@ -72,10 +72,10 @@ class Sscanf extends ScanfFunction { Sscanf() { this instanceof TopLevelFunction and ( - hasName("sscanf") or // sscanf(src_stream, format, args...) - hasName("swscanf") or // swscanf(src, format, args...) - hasName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) - hasName("_swscanf_l") // _swscanf_l(src, format, locale, args...) + hasGlobalOrStdishName("sscanf") or // sscanf(src_stream, format, args...) + hasGlobalOrStdishName("swscanf") or // swscanf(src, format, args...) + hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) + hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...) ) } @@ -91,10 +91,10 @@ class Snscanf extends ScanfFunction { Snscanf() { this instanceof TopLevelFunction and ( - hasName("_snscanf") or // _snscanf(src, max_amount, format, args...) - hasName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) - hasName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...) - hasName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...) + hasGlobalName("_snscanf") or // _snscanf(src, max_amount, format, args...) + hasGlobalName("_snwscanf") or // _snwscanf(src, max_amount, format, args...) + hasGlobalName("_snscanf_l") or // _snscanf_l(src, max_amount, format, locale, args...) + hasGlobalName("_snwscanf_l") // _snwscanf_l(src, max_amount, format, locale, args...) // note that the max_amount is not a limit on the output length, it's an input length // limit used with non null-terminated strings. ) From b6b90b59eb7f3d06c7fd5e81e30aa2530d330b69 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 16:22:52 +0000 Subject: [PATCH 371/429] C++: Model bsl functions in SmartPointer.qll. --- .../semmle/code/cpp/models/implementations/SmartPointer.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll index b13b4a8801d..c6152624792 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/SmartPointer.qll @@ -4,14 +4,14 @@ import semmle.code.cpp.models.interfaces.Taint * The `std::shared_ptr` and `std::unique_ptr` template classes. */ private class UniqueOrSharedPtr extends Class { - UniqueOrSharedPtr() { this.hasQualifiedName("std", ["shared_ptr", "unique_ptr"]) } + UniqueOrSharedPtr() { this.hasQualifiedName(["std", "bsl"], ["shared_ptr", "unique_ptr"]) } } /** * The `std::make_shared` and `std::make_unique` template functions. */ private class MakeUniqueOrShared extends TaintFunction { - MakeUniqueOrShared() { this.hasQualifiedName("std", ["make_shared", "make_unique"]) } + MakeUniqueOrShared() { this.hasQualifiedName(["bsl", "std"], ["make_shared", "make_unique"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // Exclude the specializations of `std::make_shared` and `std::make_unique` that allocate arrays From 8c4563b7e399a944a343241b6879a792d8b9f7c5 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 5 Feb 2021 11:19:23 +0100 Subject: [PATCH 372/429] Code quality improvements --- .../Populators/CompilationUnitVisitor.cs | 10 ++--- .../Populators/TypeContainerVisitor.cs | 40 +++++++++++-------- .../Populators/TypeOrNamespaceVisitor.cs | 4 +- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs index 72f015464a3..c8adceebe38 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -13,30 +13,30 @@ namespace Semmle.Extraction.CSharp.Populators public override void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) { // This information is not yet extracted. - cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), cx.CreateLocation(node.GetLocation()), "", Severity.Info); + Cx.ExtractionError("Not implemented extern alias directive", node.ToFullString(), Cx.CreateLocation(node.GetLocation()), "", Severity.Info); } public override void VisitCompilationUnit(CompilationUnitSyntax compilationUnit) { foreach (var m in compilationUnit.ChildNodes()) { - cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); + Cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); } // Gather comments: foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true)) { - CommentPopulator.ExtractComment(cx, trivia); + CommentPopulator.ExtractComment(Cx, trivia); } foreach (var trivia in compilationUnit.GetLeadingTrivia()) { - CommentPopulator.ExtractComment(cx, trivia); + CommentPopulator.ExtractComment(Cx, trivia); } foreach (var trivia in compilationUnit.GetTrailingTrivia()) { - CommentPopulator.ExtractComment(cx, trivia); + CommentPopulator.ExtractComment(Cx, trivia); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs index 6e5b45e9e3a..f72de1c2f08 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs @@ -11,16 +11,17 @@ namespace Semmle.Extraction.CSharp.Populators { public class TypeContainerVisitor : CSharpSyntaxVisitor { - protected Context cx { get; } - protected IEntity parent { get; } - protected TextWriter trapFile { get; } + protected Context Cx { get; } + protected IEntity Parent { get; } + protected TextWriter TrapFile { get; } private readonly Lazy> attributeLookup; public TypeContainerVisitor(Context cx, TextWriter trapFile, IEntity parent) { - this.cx = cx; - this.parent = parent; - this.trapFile = trapFile; + Cx = cx; + Parent = parent; + TrapFile = trapFile; + attributeLookup = new Lazy>(() => { var dict = new Dictionary(); @@ -40,46 +41,51 @@ namespace Semmle.Extraction.CSharp.Populators public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) { - Entities.NamedType.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); + Entities.NamedType.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent); } public override void VisitRecordDeclaration(RecordDeclarationSyntax node) { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); + ExtractTypeDeclaration(node); } - public override void VisitClassDeclaration(ClassDeclarationSyntax classDecl) + public override void VisitClassDeclaration(ClassDeclarationSyntax node) { - Entities.Type.Create(cx, cx.GetModel(classDecl).GetDeclaredSymbol(classDecl)).ExtractRecursive(trapFile, parent); + ExtractTypeDeclaration(node); } public override void VisitStructDeclaration(StructDeclarationSyntax node) { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); + ExtractTypeDeclaration(node); } public override void VisitEnumDeclaration(EnumDeclarationSyntax node) { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); + ExtractTypeDeclaration(node); } public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) { - Entities.Type.Create(cx, cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(trapFile, parent); + ExtractTypeDeclaration(node); + } + + private void ExtractTypeDeclaration(BaseTypeDeclarationSyntax node) + { + Entities.Type.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent); } public override void VisitAttributeList(AttributeListSyntax node) { - if (cx.Extractor.Standalone) + if (Cx.Extractor.Standalone) return; - var outputAssembly = Assembly.CreateOutputAssembly(cx); + var outputAssembly = Assembly.CreateOutputAssembly(Cx); foreach (var attribute in node.Attributes) { if (attributeLookup.Value(attribute) is AttributeData attributeData) { - var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(cx, attributeData, outputAssembly); - cx.BindComments(ae, attribute.GetLocation()); + var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(Cx, attributeData, outputAssembly); + Cx.BindComments(ae, attribute.GetLocation()); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs index aacdc5d2a4f..a3daae08a60 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeOrNamespaceVisitor.cs @@ -13,12 +13,12 @@ namespace Semmle.Extraction.CSharp.Populators { // Only deal with "using namespace" not "using X = Y" if (usingDirective.Alias == null) - new UsingDirective(cx, usingDirective, (NamespaceDeclaration)parent); + new UsingDirective(Cx, usingDirective, (NamespaceDeclaration)Parent); } public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) { - NamespaceDeclaration.Create(cx, node, (NamespaceDeclaration)parent); + NamespaceDeclaration.Create(Cx, node, (NamespaceDeclaration)Parent); } } } From 595bb025f9601ac72717a5b4d77625167c9e6cda Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 16:34:07 +0000 Subject: [PATCH 373/429] C++: Model bsl functions in StdMap.qll. --- .../cpp/models/implementations/StdMap.qll | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll index f261038735d..baf4774ce76 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll @@ -5,13 +5,20 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Iterator +/** + * The `std::map` and `std::unordered_map` template classes. + */ +private class MapOrUnorderedMap extends Class { + MapOrUnorderedMap() { this.hasQualifiedName(["std", "bsl"], ["map", "unordered_map"]) } +} + /** * Additional model for map constructors using iterator inputs. */ private class StdMapConstructor extends Constructor, TaintFunction { StdMapConstructor() { - this.hasQualifiedName("std", "map", "map") or - this.hasQualifiedName("std", "unordered_map", "unordered_map") + this.hasQualifiedName(["std", "bsl"], "map", "map") or + this.hasQualifiedName(["std", "bsl"], "unordered_map", "unordered_map") } /** @@ -37,7 +44,8 @@ private class StdMapConstructor extends Constructor, TaintFunction { */ private class StdMapInsert extends TaintFunction { StdMapInsert() { - this.hasQualifiedName("std", ["map", "unordered_map"], ["insert", "insert_or_assign"]) + this.hasName(["insert", "insert_or_assign"]) and + this.getDeclaringType() instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -56,7 +64,8 @@ private class StdMapInsert extends TaintFunction { */ private class StdMapEmplace extends TaintFunction { StdMapEmplace() { - this.hasQualifiedName("std", ["map", "unordered_map"], ["emplace", "emplace_hint"]) + this.hasName(["emplace", "emplace_hint"]) and + this.getDeclaringType() instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -79,7 +88,10 @@ private class StdMapEmplace extends TaintFunction { * The standard map `try_emplace` function. */ private class StdMapTryEmplace extends TaintFunction { - StdMapTryEmplace() { this.hasQualifiedName("std", ["map", "unordered_map"], "try_emplace") } + StdMapTryEmplace() { + this.hasName("try_emplace") and + this.getDeclaringType() instanceof MapOrUnorderedMap + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter apart from the key to qualifier and return value @@ -106,7 +118,10 @@ private class StdMapTryEmplace extends TaintFunction { * The standard map `merge` function. */ private class StdMapMerge extends TaintFunction { - StdMapMerge() { this.hasQualifiedName("std", ["map", "unordered_map"], "merge") } + StdMapMerge() { + this.hasName("merge") and + this.getDeclaringType() instanceof MapOrUnorderedMap + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // container1.merge(container2) @@ -119,7 +134,10 @@ private class StdMapMerge extends TaintFunction { * The standard map functions `at` and `operator[]`. */ private class StdMapAt extends TaintFunction { - StdMapAt() { this.hasQualifiedName("std", ["map", "unordered_map"], ["at", "operator[]"]) } + StdMapAt() { + this.hasName(["at", "operator[]"]) and + this.getDeclaringType() instanceof MapOrUnorderedMap + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to referenced return value @@ -136,7 +154,10 @@ private class StdMapAt extends TaintFunction { * The standard map `find` function. */ private class StdMapFind extends TaintFunction { - StdMapFind() { this.hasQualifiedName("std", ["map", "unordered_map"], "find") } + StdMapFind() { + this.hasName("find") and + this.getDeclaringType() instanceof MapOrUnorderedMap + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -148,7 +169,10 @@ private class StdMapFind extends TaintFunction { * The standard map `erase` function. */ private class StdMapErase extends TaintFunction { - StdMapErase() { this.hasQualifiedName("std", ["map", "unordered_map"], "erase") } + StdMapErase() { + this.hasName("erase") and + this.getDeclaringType() instanceof MapOrUnorderedMap + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value @@ -163,8 +187,8 @@ private class StdMapErase extends TaintFunction { */ private class StdMapEqualRange extends TaintFunction { StdMapEqualRange() { - this.hasQualifiedName("std", ["map", "unordered_map"], - ["lower_bound", "upper_bound", "equal_range"]) + this.hasName(["lower_bound", "upper_bound", "equal_range"]) and + this.getDeclaringType() instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From 4a0791200696089d69a8f24da130321187d89463 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Mon, 15 Feb 2021 16:36:49 +0000 Subject: [PATCH 374/429] C++: Small code improvement. --- cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll index baf4774ce76..6925fb110fc 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll @@ -16,10 +16,7 @@ private class MapOrUnorderedMap extends Class { * Additional model for map constructors using iterator inputs. */ private class StdMapConstructor extends Constructor, TaintFunction { - StdMapConstructor() { - this.hasQualifiedName(["std", "bsl"], "map", "map") or - this.hasQualifiedName(["std", "bsl"], "unordered_map", "unordered_map") - } + StdMapConstructor() { this.getDeclaringType() instanceof MapOrUnorderedMap } /** * Gets the index of a parameter to this function that is an iterator. From 6a4b54ec892a0e8e4bebd0d790d9ba02146afdc3 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 13 Nov 2020 18:25:41 +0100 Subject: [PATCH 375/429] C#: Extract global statements --- .../Entities/OrdinaryMethod.cs | 5 +++ .../Entities/Statement.cs | 36 +++++++++++++--- .../Entities/Statement`1.cs | 32 +++++---------- .../Entities/Statements/Factory.cs | 2 +- .../Statements/GlobalStatementsBlock.cs | 41 +++++++++++++++++++ .../Populators/CompilationUnitVisitor.cs | 30 ++++++++++++++ .../Populators/TypeContainerVisitor.cs | 8 +++- .../Semmle.Extraction.CSharp/Tuples.cs | 10 +++++ csharp/ql/src/semmle/code/csharp/Callable.qll | 3 ++ csharp/ql/src/semmle/code/csharp/PrintAst.qll | 3 +- csharp/ql/src/semmle/code/csharp/Stmt.qll | 6 +++ csharp/ql/src/semmlecode.csharp.dbscheme | 5 +++ .../test/library-tests/csharp9/GlobalStmt.cs | 25 +++++++++++ .../csharp9/LocalFunctions.expected | 1 + .../library-tests/csharp9/PrintAst.expected | 31 ++++++++++++++ .../library-tests/csharp9/globalStmt.expected | 10 +++++ .../test/library-tests/csharp9/globalStmt.ql | 15 +++++++ 17 files changed, 232 insertions(+), 31 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs create mode 100644 csharp/ql/test/library-tests/csharp9/GlobalStmt.cs create mode 100644 csharp/ql/test/library-tests/csharp9/globalStmt.expected create mode 100644 csharp/ql/test/library-tests/csharp9/globalStmt.ql diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index d81fc25f72b..d9e95c342ac 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -51,6 +51,11 @@ namespace Semmle.Extraction.CSharp.Entities Overrides(trapFile); ExtractRefReturn(trapFile, symbol, this); ExtractCompilerGenerated(trapFile); + + if (SymbolEqualityComparer.Default.Equals(symbol, Context.Compilation.GetEntryPoint(System.Threading.CancellationToken.None))) + { + trapFile.entry_methods(this); + } } public static new OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs index 7a5bdcd2a58..94ab9a7ce61 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement.cs @@ -1,13 +1,41 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp; +using System.IO; namespace Semmle.Extraction.CSharp.Entities { internal abstract class Statement : FreshEntity, IExpressionParentEntity, IStatementParentEntity { - protected Statement(Context cx) : base(cx) { } + private readonly int child; + private readonly Kinds.StmtKind kind; + private readonly IStatementParentEntity parent; - public static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) => + protected Statement(Context cx, Kinds.StmtKind kind, IStatementParentEntity parent, int child) + : base(cx) + { + this.kind = kind; + this.parent = parent; + this.child = child; + } + + protected override void Populate(TextWriter trapFile) + { + trapFile.statements(this, kind); + if (parent.IsTopLevelParent) + { + trapFile.stmt_parent_top_level(this, child, parent); + } + else + { + trapFile.stmt_parent(this, child, parent); + } + + PopulateStatement(trapFile); + } + + protected abstract void PopulateStatement(TextWriter trapFile); + + public static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child) => Statements.Factory.Create(cx, node, parent, child); /// @@ -16,14 +44,10 @@ namespace Semmle.Extraction.CSharp.Entities /// public virtual int NumberOfStatements => 1; - public override Microsoft.CodeAnalysis.Location ReportingLocation => GetStatementSyntax().GetLocation(); - bool IExpressionParentEntity.IsTopLevelParent => false; bool IStatementParentEntity.IsTopLevelParent => false; - protected abstract CSharpSyntaxNode GetStatementSyntax(); - public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs index 1d8dd43f702..8ea6650d4f7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statement`1.cs @@ -8,40 +8,28 @@ namespace Semmle.Extraction.CSharp.Entities internal abstract class Statement : Statement where TSyntax : CSharpSyntaxNode { protected readonly TSyntax Stmt; - private readonly int child; - private readonly Kinds.StmtKind kind; - private readonly IStatementParentEntity parent; private readonly Location location; - protected override CSharpSyntaxNode GetStatementSyntax() => Stmt; - protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child, Location location) - : base(cx) + : base(cx, kind, parent, child) { Stmt = stmt; - this.parent = parent; - this.child = child; this.location = location; - this.kind = kind; cx.BindComments(this, location.symbol); } - protected sealed override void Populate(TextWriter trapFile) - { - trapFile.statements(this, kind); - if (parent.IsTopLevelParent) - trapFile.stmt_parent_top_level(this, child, parent); - else - trapFile.stmt_parent(this, child, parent); - trapFile.stmt_location(this, location); - PopulateStatement(trapFile); - } - - protected abstract void PopulateStatement(TextWriter trapFile); - protected Statement(Context cx, TSyntax stmt, Kinds.StmtKind kind, IStatementParentEntity parent, int child) : this(cx, stmt, kind, parent, child, cx.CreateLocation(stmt.FixedLocation())) { } + protected sealed override void Populate(TextWriter trapFile) + { + base.Populate(trapFile); + + trapFile.stmt_location(this, location); + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation => Stmt.GetLocation(); + public override string ToString() => Label.ToString(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs index 69ebdca1c16..2960982061e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Factory.cs @@ -5,7 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal static class Factory { - internal static Statement Create(Context cx, StatementSyntax node, Statement parent, int child) + internal static Statement Create(Context cx, StatementSyntax node, IStatementParentEntity parent, int child) { switch (node.Kind()) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs new file mode 100644 index 00000000000..ca1d5ba2c5b --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs @@ -0,0 +1,41 @@ +using Semmle.Extraction.Kinds; +using System.Linq; +using System.IO; +using Semmle.Extraction.Entities; + +namespace Semmle.Extraction.CSharp.Entities.Statements +{ + internal class GlobalStatementsBlock : Statement + { + private GlobalStatementsBlock(Context cx, Method parent) + : base(cx, StmtKind.BLOCK, parent, 0) { } + + public override Microsoft.CodeAnalysis.Location ReportingLocation + { + get + { + // We only create a `GlobalStatementsBlock` if there are global statements. This also means that the + // entry point is going to be the generated method around those global statements + return cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None) + ?.DeclaringSyntaxReferences + .FirstOrDefault() + ?.GetSyntax() + .GetLocation(); + } + } + + public static GlobalStatementsBlock Create(Context cx, Method parent) + { + var ret = new GlobalStatementsBlock(cx, parent); + ret.TryPopulate(); + return ret; + } + + protected override void PopulateStatement(TextWriter trapFile) + { + trapFile.global_stmt_block(this); + + trapFile.stmt_location(this, cx.CreateLocation(ReportingLocation)); + } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs index c8adceebe38..58e5404ccd7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/CompilationUnitVisitor.cs @@ -2,6 +2,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Util.Logging; +using Semmle.Extraction.CSharp.Entities; +using Semmle.Extraction.CSharp.Entities.Statements; +using System.Linq; namespace Semmle.Extraction.CSharp.Populators { @@ -23,6 +26,8 @@ namespace Semmle.Extraction.CSharp.Populators Cx.Try(m, null, () => ((CSharpSyntaxNode)m).Accept(this)); } + ExtractGlobalStatements(compilationUnit); + // Gather comments: foreach (var trivia in compilationUnit.DescendantTrivia(compilationUnit.Span, descendIntoTrivia: true)) { @@ -39,5 +44,30 @@ namespace Semmle.Extraction.CSharp.Populators CommentPopulator.ExtractComment(Cx, trivia); } } + + private void ExtractGlobalStatements(CompilationUnitSyntax compilationUnit) + { + var globalStatements = compilationUnit + .ChildNodes() + .OfType() + .ToList(); + + if (!globalStatements.Any()) + { + return; + } + + var entryPoint = Cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None); + var entryMethod = Method.Create(Cx, entryPoint); + var block = GlobalStatementsBlock.Create(Cx, entryMethod); + + for (var i = 0; i < globalStatements.Count; i++) + { + if (globalStatements[i].Statement is object) + { + Statement.Create(Cx, globalStatements[i].Statement, block, i); + } + } + } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs index f72de1c2f08..ededf2978b9 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Populators/TypeContainerVisitor.cs @@ -39,6 +39,12 @@ namespace Semmle.Extraction.CSharp.Populators throw new InternalError(node, "Unhandled top-level syntax node"); } + public override void VisitGlobalStatement(GlobalStatementSyntax node) + { + // Intentionally left empty. + // Global statements are handled in CompilationUnitVisitor + } + public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) { Entities.NamedType.Create(Cx, Cx.GetModel(node).GetDeclaredSymbol(node)).ExtractRecursive(TrapFile, Parent); @@ -84,7 +90,7 @@ namespace Semmle.Extraction.CSharp.Populators { if (attributeLookup.Value(attribute) is AttributeData attributeData) { - var ae = Semmle.Extraction.CSharp.Entities.Attribute.Create(Cx, attributeData, outputAssembly); + var ae = Entities.Attribute.Create(Cx, attributeData, outputAssembly); Cx.BindComments(ae, attribute.GetLocation()); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index df39d6a836c..75c0f633cc0 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -379,6 +379,11 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("methods", method, name, declType, retType, originalDefinition); } + internal static void entry_methods(this TextWriter trapFile, Method method) + { + trapFile.WriteTuple("entry_methods", method); + } + internal static void modifiers(this TextWriter trapFile, Label entity, string modifier) { trapFile.WriteTuple("modifiers", entity, modifier); @@ -509,6 +514,11 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("stackalloc_array_creation", array); } + internal static void global_stmt_block(this TextWriter trapFile, Entities.Statements.GlobalStatementsBlock block) + { + trapFile.WriteTuple("global_stmt_block", block); + } + internal static void stmt_location(this TextWriter trapFile, Statement stmt, Location location) { trapFile.WriteTuple("stmt_location", stmt, location); diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 7238f4576f9..8f2c1bd4471 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -292,6 +292,9 @@ class Method extends Callable, Virtualizable, Attributable, @method { } override string getAPrimaryQlClass() { result = "Method" } + + /** Holds if this method is the entry method of the compilation. */ + predicate isEntry() { entry_methods(this) } } /** diff --git a/csharp/ql/src/semmle/code/csharp/PrintAst.qll b/csharp/ql/src/semmle/code/csharp/PrintAst.qll index 024dfc2a05e..1cac4a5f238 100644 --- a/csharp/ql/src/semmle/code/csharp/PrintAst.qll +++ b/csharp/ql/src/semmle/code/csharp/PrintAst.qll @@ -134,7 +134,8 @@ private newtype TPrintAstNode = TParametersNode(Parameterizable parameterizable) { shouldPrint(parameterizable, _) and parameterizable.getNumberOfParameters() > 0 and - not isNotNeeded(parameterizable) + not isNotNeeded(parameterizable) and + exists(Parameter p | p.getDeclaringElement() = parameterizable and shouldPrint(p, _)) } or TAttributesNode(Attributable attributable) { shouldPrint(attributable, _) and diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 15199896390..aaa8890cd34 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -33,6 +33,9 @@ class Stmt extends ControlFlowElement, @stmt { override Location getALocation() { stmt_location(this, result) } + /** Holds if this statement is a global statement. */ + predicate isGlobal() { this.getParent().(BlockStmt).isGlobalStatementContainer() } + /** * Gets the singleton statement contained in this statement, by removing * enclosing block statements. @@ -70,6 +73,9 @@ class BlockStmt extends Stmt, @block_stmt { /** Holds if this block is an empty block with no statements. */ predicate isEmpty() { not exists(this.getAStmt()) } + /** Holds if this block is the container of the global statements. */ + predicate isGlobalStatementContainer() { global_stmt_block(this) } + override Stmt stripSingletonBlocks() { if getNumberOfStmts() = 1 then result = getAChildStmt().stripSingletonBlocks() diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 16936565fbe..1cea35ace06 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -843,6 +843,9 @@ local_function_stmts( unique int fn: @local_function_stmt ref, int stmt: @local_function ref); +entry_methods( + unique int id: @method ref); + /** VARIABLES **/ @variable = @local_scope_variable | @field; @@ -972,6 +975,8 @@ case @stmt.kind of @goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; +global_stmt_block( + unique int id: @block_stmt ref); stmt_location( unique int id: @stmt ref, diff --git a/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs b/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs new file mode 100644 index 00000000000..6b8958d7fbd --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/GlobalStmt.cs @@ -0,0 +1,25 @@ +/* + Global statements are not allowed in 'library' target. + + semmle-extractor-options: --standalone +*/ + +using System; + +[assembly: Attr] // not a global stmt + +Console.WriteLine("1"); +Console.WriteLine("2"); +M(); + +void M() +{ +} + +public class Attr : Attribute +{ + void M1() + { + Console.WriteLine("3"); + } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected b/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected index fd746b2a58b..c57ece05e59 100644 --- a/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected +++ b/csharp/ql/test/library-tests/csharp9/LocalFunctions.expected @@ -1,6 +1,7 @@ noBody | LocalFunction.cs:16:9:16:41 | localExtern | localFunctionModifier +| GlobalStmt.cs:15:1:17:1 | M | private | | LambdaModifier.cs:8:9:8:36 | m | private | | LocalFunction.cs:9:9:12:9 | mul | async | | LocalFunction.cs:9:9:12:9 | mul | private | diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index e203842664b..66dc25dfedb 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -389,6 +389,37 @@ FunctionPointer.cs: # 50| 14: [Class] B #-----| 3: (Base types) # 50| 0: [TypeMention] A +GlobalStmt.cs: +# 7| [Class] $ +# 7| 4: [Method]
    $ +# 7| 4: [BlockStmt] {...} +# 11| 0: [ExprStmt] ...; +# 11| 0: [MethodCall] call to method WriteLine +# 11| -1: [TypeAccess] access to type Console +# 11| 0: [TypeMention] Console +# 11| 0: [StringLiteral] "1" +# 12| 1: [ExprStmt] ...; +# 12| 0: [MethodCall] call to method WriteLine +# 12| -1: [TypeAccess] access to type Console +# 12| 0: [TypeMention] Console +# 12| 0: [StringLiteral] "2" +# 13| 2: [ExprStmt] ...; +# 13| 0: [LocalFunctionCall] call to local function M +# 13| -1: [LocalFunctionAccess] access to local function M +# 15| 3: [LocalFunctionStmt] M(...) +# 15| 0: [LocalFunction] M +# 16| 4: [BlockStmt] {...} +# 19| [Class] Attr +#-----| 3: (Base types) +# 19| 0: [TypeMention] Attribute +# 21| 5: [Method] M1 +# 21| -1: [TypeMention] Void +# 22| 4: [BlockStmt] {...} +# 23| 0: [ExprStmt] ...; +# 23| 0: [MethodCall] call to method WriteLine +# 23| -1: [TypeAccess] access to type Console +# 23| 0: [TypeMention] Console +# 23| 0: [StringLiteral] "3" InitOnlyProperty.cs: # 3| [Class] Base # 5| 5: [Property] Prop0 diff --git a/csharp/ql/test/library-tests/csharp9/globalStmt.expected b/csharp/ql/test/library-tests/csharp9/globalStmt.expected new file mode 100644 index 00000000000..7063a67d6bc --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/globalStmt.expected @@ -0,0 +1,10 @@ +global_stmt +| GlobalStmt.cs:11:1:11:23 | ...; | +| GlobalStmt.cs:12:1:12:23 | ...; | +| GlobalStmt.cs:13:1:13:4 | ...; | +| GlobalStmt.cs:15:1:17:1 | M(...) | +globalBlock +| GlobalStmt.cs:7:1:25:1 | {...} | GlobalStmt.cs:7:1:25:1 |
    $ | file://:0:0:0:0 | args | GlobalStmt.cs:7:1:25:1 | $ | +methods +| GlobalStmt.cs:7:1:25:1 |
    $ | entry | +| GlobalStmt.cs:21:8:21:9 | M1 | non-entry | diff --git a/csharp/ql/test/library-tests/csharp9/globalStmt.ql b/csharp/ql/test/library-tests/csharp9/globalStmt.ql new file mode 100644 index 00000000000..586f34d4ade --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/globalStmt.ql @@ -0,0 +1,15 @@ +import csharp + +query predicate global_stmt(Stmt stmt) { stmt.isGlobal() } + +query predicate globalBlock(BlockStmt block, Method m, Parameter p, Type t) { + block.isGlobalStatementContainer() and + block.getEnclosingCallable() = m and + m.getDeclaringType() = t and + m.getAParameter() = p +} + +query predicate methods(Method m, string entry) { + m.getFile().getStem() = "GlobalStmt" and + if m.isEntry() then entry = "entry" else entry = "non-entry" +} From b79d5ab44b4eb9716cd942b1d56de6739ce16049 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 8 Dec 2020 11:22:34 +0100 Subject: [PATCH 376/429] Fix labeled stmt factory method parameter types --- .../Entities/Statements/Labeled.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs index 1fce622b347..fe69af917ba 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs @@ -6,17 +6,18 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal class Labeled : Statement { - private readonly Statement parent; + private readonly IStatementParentEntity parent; private readonly int child; + private Statement labelledStmt; - private Labeled(Context cx, LabeledStatementSyntax stmt, Statement parent, int child) + private Labeled(Context cx, LabeledStatementSyntax stmt, IStatementParentEntity parent, int child) : base(cx, stmt, StmtKind.LABEL, parent, child) { this.parent = parent; this.child = child; } - public static Labeled Create(Context cx, LabeledStatementSyntax node, Statement parent, int child) + public static Labeled Create(Context cx, LabeledStatementSyntax node, IStatementParentEntity parent, int child) { var ret = new Labeled(cx, node, parent, child); ret.TryPopulate(); @@ -27,13 +28,11 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { trapFile.exprorstmt_name(this, Stmt.Identifier.ToString()); - // For compatilibty with the Mono extractor, make insert the labelled statement into the same block + // For compatibility with the Mono extractor, make insert the labelled statement into the same block // as this one. The parent MUST be a block statement. labelledStmt = Statement.Create(cx, Stmt.Statement, parent, child + 1); } - private Statement labelledStmt; - public override int NumberOfStatements => 1 + labelledStmt.NumberOfStatements; } } From 423fee3069a87882686ff8669245c9218f37e5ef Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 2 Feb 2021 09:13:26 +0100 Subject: [PATCH 377/429] Fix argument location of top level statement entry point --- .../Semmle.Extraction.CSharp/Entities/Parameter.cs | 7 +++++++ csharp/ql/test/library-tests/csharp9/PrintAst.expected | 2 ++ csharp/ql/test/library-tests/csharp9/globalStmt.expected | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index 325a77b6dd2..9a8e6765804 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -112,6 +112,13 @@ namespace Semmle.Extraction.CSharp.Entities foreach (var l in symbol.Locations) trapFile.param_location(this, Context.CreateLocation(l)); + if (!symbol.Locations.Any() && + symbol.ContainingSymbol is IMethodSymbol ms && + ms.Name == WellKnownMemberNames.TopLevelStatementsEntryPointMethodName) + { + trapFile.param_location(this, Context.CreateLocation()); + } + if (!IsSourceDeclaration || !symbol.FromSource()) return; diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index 66dc25dfedb..e09c7067139 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -392,6 +392,8 @@ FunctionPointer.cs: GlobalStmt.cs: # 7| [Class] $ # 7| 4: [Method]
    $ +#-----| 2: (Parameters) +# 1| 0: [Parameter] args # 7| 4: [BlockStmt] {...} # 11| 0: [ExprStmt] ...; # 11| 0: [MethodCall] call to method WriteLine diff --git a/csharp/ql/test/library-tests/csharp9/globalStmt.expected b/csharp/ql/test/library-tests/csharp9/globalStmt.expected index 7063a67d6bc..dc7ccea6ad1 100644 --- a/csharp/ql/test/library-tests/csharp9/globalStmt.expected +++ b/csharp/ql/test/library-tests/csharp9/globalStmt.expected @@ -4,7 +4,7 @@ global_stmt | GlobalStmt.cs:13:1:13:4 | ...; | | GlobalStmt.cs:15:1:17:1 | M(...) | globalBlock -| GlobalStmt.cs:7:1:25:1 | {...} | GlobalStmt.cs:7:1:25:1 |
    $ | file://:0:0:0:0 | args | GlobalStmt.cs:7:1:25:1 | $ | +| GlobalStmt.cs:7:1:25:1 | {...} | GlobalStmt.cs:7:1:25:1 |
    $ | GlobalStmt.cs:1:1:1:0 | args | GlobalStmt.cs:7:1:25:1 | $ | methods | GlobalStmt.cs:7:1:25:1 |
    $ | entry | | GlobalStmt.cs:21:8:21:9 | M1 | non-entry | From a14db7a04f905be8b886a4992aebe325fe7abcfb Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 12 Feb 2021 12:27:38 +0100 Subject: [PATCH 378/429] Fix code review findings --- .../extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs index 9a8e6765804..bb87fccdd74 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Parameter.cs @@ -114,7 +114,8 @@ namespace Semmle.Extraction.CSharp.Entities if (!symbol.Locations.Any() && symbol.ContainingSymbol is IMethodSymbol ms && - ms.Name == WellKnownMemberNames.TopLevelStatementsEntryPointMethodName) + ms.Name == WellKnownMemberNames.TopLevelStatementsEntryPointMethodName && + ms.ContainingType.Name == WellKnownMemberNames.TopLevelStatementsEntryPointTypeName) { trapFile.param_location(this, Context.CreateLocation()); } From 4967664d0904f1cc543df508dfdf7d7f0512fa01 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 12 Feb 2021 12:37:15 +0100 Subject: [PATCH 379/429] Rework global statement extraction without DB scheme change --- .../Entities/OrdinaryMethod.cs | 5 ----- .../Entities/Statements/GlobalStatementsBlock.cs | 13 +++++++------ csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs | 10 ---------- csharp/ql/src/semmle/code/csharp/Callable.qll | 3 --- csharp/ql/src/semmle/code/csharp/Stmt.qll | 4 +++- csharp/ql/src/semmle/code/csharp/commons/Util.qll | 6 +++++- csharp/ql/src/semmlecode.csharp.dbscheme | 5 ----- csharp/ql/test/library-tests/csharp9/globalStmt.ql | 3 ++- 8 files changed, 17 insertions(+), 32 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs index d9e95c342ac..d81fc25f72b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/OrdinaryMethod.cs @@ -51,11 +51,6 @@ namespace Semmle.Extraction.CSharp.Entities Overrides(trapFile); ExtractRefReturn(trapFile, symbol, this); ExtractCompilerGenerated(trapFile); - - if (SymbolEqualityComparer.Default.Equals(symbol, Context.Compilation.GetEntryPoint(System.Threading.CancellationToken.None))) - { - trapFile.entry_methods(this); - } } public static new OrdinaryMethod Create(Context cx, IMethodSymbol method) => OrdinaryMethodFactory.Instance.CreateEntityFromSymbol(cx, method); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs index ca1d5ba2c5b..062a09e3fae 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/GlobalStatementsBlock.cs @@ -7,16 +7,19 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { internal class GlobalStatementsBlock : Statement { + private readonly Method parent; + private GlobalStatementsBlock(Context cx, Method parent) - : base(cx, StmtKind.BLOCK, parent, 0) { } + : base(cx, StmtKind.BLOCK, parent, 0) + { + this.parent = parent; + } public override Microsoft.CodeAnalysis.Location ReportingLocation { get { - // We only create a `GlobalStatementsBlock` if there are global statements. This also means that the - // entry point is going to be the generated method around those global statements - return cx.Compilation.GetEntryPoint(System.Threading.CancellationToken.None) + return parent.symbol ?.DeclaringSyntaxReferences .FirstOrDefault() ?.GetSyntax() @@ -33,8 +36,6 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - trapFile.global_stmt_block(this); - trapFile.stmt_location(this, cx.CreateLocation(ReportingLocation)); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index 75c0f633cc0..df39d6a836c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -379,11 +379,6 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("methods", method, name, declType, retType, originalDefinition); } - internal static void entry_methods(this TextWriter trapFile, Method method) - { - trapFile.WriteTuple("entry_methods", method); - } - internal static void modifiers(this TextWriter trapFile, Label entity, string modifier) { trapFile.WriteTuple("modifiers", entity, modifier); @@ -514,11 +509,6 @@ namespace Semmle.Extraction.CSharp trapFile.WriteTuple("stackalloc_array_creation", array); } - internal static void global_stmt_block(this TextWriter trapFile, Entities.Statements.GlobalStatementsBlock block) - { - trapFile.WriteTuple("global_stmt_block", block); - } - internal static void stmt_location(this TextWriter trapFile, Statement stmt, Location location) { trapFile.WriteTuple("stmt_location", stmt, location); diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 8f2c1bd4471..7238f4576f9 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -292,9 +292,6 @@ class Method extends Callable, Virtualizable, Attributable, @method { } override string getAPrimaryQlClass() { result = "Method" } - - /** Holds if this method is the entry method of the compilation. */ - predicate isEntry() { entry_methods(this) } } /** diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index aaa8890cd34..375e698d1cb 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -74,7 +74,9 @@ class BlockStmt extends Stmt, @block_stmt { predicate isEmpty() { not exists(this.getAStmt()) } /** Holds if this block is the container of the global statements. */ - predicate isGlobalStatementContainer() { global_stmt_block(this) } + predicate isGlobalStatementContainer() { + this.getEnclosingCallable().hasQualifiedName("$.
    $") + } override Stmt stripSingletonBlocks() { if getNumberOfStmts() = 1 diff --git a/csharp/ql/src/semmle/code/csharp/commons/Util.qll b/csharp/ql/src/semmle/code/csharp/commons/Util.qll index 203d84cbef6..10a0dce936c 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Util.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Util.qll @@ -5,7 +5,11 @@ import csharp /** A `Main` method. */ class MainMethod extends Method { MainMethod() { - this.hasName("Main") and + ( + this.hasName("Main") + or + this.hasQualifiedName("$.
    $") + ) and this.isStatic() and (this.getReturnType() instanceof VoidType or this.getReturnType() instanceof IntType) and if this.getNumberOfParameters() = 1 diff --git a/csharp/ql/src/semmlecode.csharp.dbscheme b/csharp/ql/src/semmlecode.csharp.dbscheme index 1cea35ace06..16936565fbe 100644 --- a/csharp/ql/src/semmlecode.csharp.dbscheme +++ b/csharp/ql/src/semmlecode.csharp.dbscheme @@ -843,9 +843,6 @@ local_function_stmts( unique int fn: @local_function_stmt ref, int stmt: @local_function ref); -entry_methods( - unique int id: @method ref); - /** VARIABLES **/ @variable = @local_scope_variable | @field; @@ -975,8 +972,6 @@ case @stmt.kind of @goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt; -global_stmt_block( - unique int id: @block_stmt ref); stmt_location( unique int id: @stmt ref, diff --git a/csharp/ql/test/library-tests/csharp9/globalStmt.ql b/csharp/ql/test/library-tests/csharp9/globalStmt.ql index 586f34d4ade..ff0ca8f661a 100644 --- a/csharp/ql/test/library-tests/csharp9/globalStmt.ql +++ b/csharp/ql/test/library-tests/csharp9/globalStmt.ql @@ -1,4 +1,5 @@ import csharp +private import semmle.code.csharp.commons.Util query predicate global_stmt(Stmt stmt) { stmt.isGlobal() } @@ -11,5 +12,5 @@ query predicate globalBlock(BlockStmt block, Method m, Parameter p, Type t) { query predicate methods(Method m, string entry) { m.getFile().getStem() = "GlobalStmt" and - if m.isEntry() then entry = "entry" else entry = "non-entry" + if m instanceof MainMethod then entry = "entry" else entry = "non-entry" } From 9bb501c595bf33d5d6af451801015914a30561b2 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 15 Feb 2021 21:30:56 +0100 Subject: [PATCH 380/429] Fix failing tests --- csharp/ql/test/library-tests/csharp9/ForeachExtension.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs b/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs index 0ef36fbc7d9..6e2af21e323 100644 --- a/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs +++ b/csharp/ql/test/library-tests/csharp9/ForeachExtension.cs @@ -46,5 +46,3 @@ class Program yield return 1; } } - -// semmle-extractor-options: /r:System.Linq.dll \ No newline at end of file From 9c2ca939862b7bc232e994667991596045a767bf Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 15 Feb 2021 21:38:02 +0100 Subject: [PATCH 381/429] Use 'Declaration::hasQualifiedName/2' in 'MainMethod' --- csharp/ql/src/semmle/code/csharp/commons/Util.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/commons/Util.qll b/csharp/ql/src/semmle/code/csharp/commons/Util.qll index 10a0dce936c..d1b9b3b7894 100644 --- a/csharp/ql/src/semmle/code/csharp/commons/Util.qll +++ b/csharp/ql/src/semmle/code/csharp/commons/Util.qll @@ -8,7 +8,7 @@ class MainMethod extends Method { ( this.hasName("Main") or - this.hasQualifiedName("$.
    $") + this.hasQualifiedName("$", "
    $") ) and this.isStatic() and (this.getReturnType() instanceof VoidType or this.getReturnType() instanceof IntType) and From 3e2a6fca21191b6a24ecb8110e55a147b1b56a71 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 10:57:16 +0100 Subject: [PATCH 382/429] C#: Simplify CIL.GenericContext contract --- .../Entities/TypeSignatureDecoder.cs | 5 ++-- .../Semmle.Extraction.CIL/GenericContext.cs | 28 +------------------ 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs index dcb986f1526..2ec82226d55 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs @@ -1,6 +1,7 @@ using System; using System.Reflection.Metadata; using System.Collections.Immutable; +using System.Linq; namespace Semmle.Extraction.CIL.Entities { @@ -29,10 +30,10 @@ namespace Semmle.Extraction.CIL.Entities genericType.Construct(typeArguments); Type ISignatureTypeProvider.GetGenericMethodParameter(GenericContext genericContext, int index) => - genericContext.GetGenericMethodParameter(index); + genericContext.MethodParameters.ElementAt(index); Type ISignatureTypeProvider.GetGenericTypeParameter(GenericContext genericContext, int index) => - genericContext.GetGenericTypeParameter(index); + genericContext.TypeParameters.ElementAt(index); Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => new ModifiedType(cx, unmodifiedType, modifier, isRequired); diff --git a/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs b/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs index 6db62bf5bbf..1e9aa21e399 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs @@ -23,34 +23,8 @@ namespace Semmle.Extraction.CIL public abstract IEnumerable TypeParameters { get; } /// - /// The list of generic method parameters. + /// The list of generic method parameters/arguments. /// public abstract IEnumerable MethodParameters { get; } - - /// - /// Gets the `p`th type parameter. - /// - /// The index of the parameter. - /// - /// For constructed types, the supplied type. - /// For unbound types, the type parameter. - /// - public Entities.Type GetGenericTypeParameter(int p) - { - return TypeParameters.ElementAt(p); - } - - /// - /// Gets the `p`th method type parameter. - /// - /// The index of the parameter. - /// - /// For constructed types, the supplied type. - /// For unbound types, the type parameter. - /// - public Entities.Type GetGenericMethodParameter(int p) - { - return MethodParameters.ElementAt(p); - } } } From 61e952766cc95f58ea61f2b674c7d4ed845bfa06 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 11:06:24 +0100 Subject: [PATCH 383/429] Convert CIL.GenericContext to interface --- .../Context.Factories.cs | 10 ++++---- .../Semmle.Extraction.CIL/Context.cs | 2 +- .../Semmle.Extraction.CIL/EmptyContext.cs | 12 ++++++---- .../Entities/DefinitionMethod.cs | 2 +- .../Entities/ExceptionRegion.cs | 4 ++-- .../Semmle.Extraction.CIL/Entities/Field.cs | 11 +++++++-- .../Entities/ITypeSignature.cs | 2 +- .../Entities/MemberReferenceField.cs | 4 ++-- .../Entities/MemberReferenceMethod.cs | 6 ++--- .../Semmle.Extraction.CIL/Entities/Method.cs | 4 ++-- .../Entities/MethodSpecificationMethod.cs | 2 +- .../Entities/MethodTypeParameter.cs | 2 +- .../Entities/Property.cs | 4 ++-- .../Entities/SignatureDecoder.cs | 24 +++++++++---------- .../Semmle.Extraction.CIL/Entities/Type.cs | 2 +- .../Entities/TypeContainer.cs | 10 ++++++-- .../Entities/TypeParameter.cs | 4 ++-- .../Entities/TypeSignatureDecoder.cs | 14 +++++------ .../{GenericContext.cs => IGenericContext.cs} | 14 ++++------- 19 files changed, 72 insertions(+), 61 deletions(-) rename csharp/extractor/Semmle.Extraction.CIL/{GenericContext.cs => IGenericContext.cs} (59%) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs index dd09727f3c0..36e420e3628 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs @@ -95,11 +95,11 @@ namespace Semmle.Extraction.CIL /// The handle of the entity. /// The generic context. /// - public IExtractedEntity CreateGeneric(GenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h]; + public IExtractedEntity CreateGeneric(IGenericContext genericContext, Handle h) => genericHandleFactory[genericContext, h]; - private readonly GenericContext defaultGenericContext; + private readonly IGenericContext defaultGenericContext; - private IExtractedEntity CreateGenericHandle(GenericContext gc, Handle handle) + private IExtractedEntity CreateGenericHandle(IGenericContext gc, Handle handle) { IExtractedEntity entity; switch (handle.Kind) @@ -136,7 +136,7 @@ namespace Semmle.Extraction.CIL return entity; } - private IExtractedEntity Create(GenericContext gc, MemberReferenceHandle handle) + private IExtractedEntity Create(IGenericContext gc, MemberReferenceHandle handle) { var mr = MdReader.GetMemberReference(handle); switch (mr.GetKind()) @@ -228,7 +228,7 @@ namespace Semmle.Extraction.CIL #endregion - private readonly CachedFunction genericHandleFactory; + private readonly CachedFunction genericHandleFactory; /// /// Gets the short name of a member, without the preceding interface qualifier. diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.cs index ae662f2e87c..99113714b7c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.cs @@ -37,7 +37,7 @@ namespace Semmle.Extraction.CIL globalNamespace = new Lazy(() => Populate(new Entities.Namespace(this, "", null))); systemNamespace = new Lazy(() => Populate(new Entities.Namespace(this, "System"))); - genericHandleFactory = new CachedFunction(CreateGenericHandle); + genericHandleFactory = new CachedFunction(CreateGenericHandle); namespaceFactory = new CachedFunction(n => CreateNamespace(MdReader.GetString(n))); namespaceDefinitionFactory = new CachedFunction(CreateNamespace); sourceFiles = new CachedFunction(path => new Entities.PdbSourceFile(this, path)); diff --git a/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs b/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs index 70c73be1151..1105bc39cba 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/EmptyContext.cs @@ -5,14 +5,18 @@ namespace Semmle.Extraction.CIL /// /// A generic context which does not contain any type parameters. /// - public class EmptyContext : GenericContext + public class EmptyContext : IGenericContext { - public EmptyContext(Context cx) : base(cx) + public EmptyContext(Context cx) { + Cx = cx; } - public override IEnumerable TypeParameters { get { yield break; } } + public Context Cx { get; } + + public IEnumerable TypeParameters { get { yield break; } } + + public IEnumerable MethodParameters { get { yield break; } } - public override IEnumerable MethodParameters { get { yield break; } } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs index 175da806597..8ff7fcf24bf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/DefinitionMethod.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CIL.Entities public override IList? LocalVariables => locals; - public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc) + public DefinitionMethod(IGenericContext gc, MethodDefinitionHandle handle) : base(gc) { md = Cx.MdReader.GetMethodDefinition(handle); this.gc = gc; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs index 75303e7903b..3026ff03030 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs @@ -7,13 +7,13 @@ namespace Semmle.Extraction.CIL.Entities /// internal class ExceptionRegion : UnlabelledEntity { - private readonly GenericContext gc; + private readonly IGenericContext gc; private readonly MethodImplementation method; private readonly int index; private readonly System.Reflection.Metadata.ExceptionRegion r; private readonly Dictionary jump_table; - public ExceptionRegion(GenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary jump_table) : base(gc.Cx) + public ExceptionRegion(IGenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary jump_table) : base(gc.Cx) { this.gc = gc; this.method = method; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs index 3f051796887..670b24b4d86 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs @@ -8,10 +8,11 @@ namespace Semmle.Extraction.CIL.Entities /// /// An entity representing a field. /// - internal abstract class Field : GenericContext, IMember, ICustomModifierReceiver + internal abstract class Field : IGenericContext, IMember, ICustomModifierReceiver { - protected Field(Context cx) : base(cx) + protected Field(Context cx) { + Cx = cx; } public Label Label { get; set; } @@ -61,5 +62,11 @@ namespace Semmle.Extraction.CIL.Entities } TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public abstract IEnumerable TypeParameters { get; } + + public abstract IEnumerable MethodParameters { get; } + + public Context Cx { get; } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs index 81dcf7b7804..beaecdfab6f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ITypeSignature.cs @@ -4,6 +4,6 @@ namespace Semmle.Extraction.CIL.Entities { internal interface ITypeSignature { - void WriteId(TextWriter trapFile, GenericContext gc); + void WriteId(TextWriter trapFile, IGenericContext gc); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs index f8017a729e8..136ece10a8c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceField.cs @@ -8,10 +8,10 @@ namespace Semmle.Extraction.CIL.Entities { private readonly MemberReferenceHandle handle; private readonly MemberReference mr; - private readonly GenericContext gc; + private readonly IGenericContext gc; private readonly Type declType; - public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.Cx) + public MemberReferenceField(IGenericContext gc, MemberReferenceHandle handle) : base(gc.Cx) { this.handle = handle; this.gc = gc; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs index cacbc6ab874..703bb717cee 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MemberReferenceMethod.cs @@ -12,10 +12,10 @@ namespace Semmle.Extraction.CIL.Entities private readonly MemberReferenceHandle handle; private readonly MemberReference mr; private readonly Type declaringType; - private readonly GenericContext parent; + private readonly IGenericContext parent; private readonly Method? sourceDeclaration; - public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc) + public MemberReferenceMethod(IGenericContext gc, MemberReferenceHandle handle) : base(gc) { this.handle = handle; this.gc = gc; @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CIL.Entities signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc); - parent = (GenericContext)Cx.CreateGeneric(gc, mr.Parent); + parent = (IGenericContext)Cx.CreateGeneric(gc, mr.Parent); var declType = parent is Method parentMethod ? parentMethod.DeclaringType diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index 30e94c8e16a..d1302837c16 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -12,10 +12,10 @@ namespace Semmle.Extraction.CIL.Entities internal abstract class Method : TypeContainer, IMember, ICustomModifierReceiver, IParameterizable { protected MethodTypeParameter[]? genericParams; - protected GenericContext gc; + protected IGenericContext gc; protected MethodSignature signature; - protected Method(GenericContext gc) : base(gc.Cx) + protected Method(IGenericContext gc) : base(gc.Cx) { this.gc = gc; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs index 26811ce6c80..a3f87b14a8e 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodSpecificationMethod.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CIL.Entities private readonly Method unboundMethod; private readonly ImmutableArray typeParams; - public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc) + public MethodSpecificationMethod(IGenericContext gc, MethodSpecificationHandle handle) : base(gc) { this.handle = handle; ms = Cx.MdReader.GetMethodSpecification(handle); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs index db5e56acb17..1795eb29269 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/MethodTypeParameter.cs @@ -21,7 +21,7 @@ namespace Semmle.Extraction.CIL.Entities public override string Name => "!" + index; - public MethodTypeParameter(GenericContext gc, Method m, int index) : base(gc) + public MethodTypeParameter(IGenericContext gc, Method m, int index) : base(gc) { method = m; this.index = index; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs index 5fb22b40409..a6c864a8cb6 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs @@ -14,9 +14,9 @@ namespace Semmle.Extraction.CIL.Entities private readonly Type type; private readonly PropertyDefinition pd; public override string IdSuffix => ";cil-property"; - private readonly GenericContext gc; + private readonly IGenericContext gc; - public Property(GenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx) + public Property(IGenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx) { this.gc = gc; this.handle = handle; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs index a955ef685c0..308846ff30a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SignatureDecoder.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CIL.Entities this.shape = shape; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('['); @@ -38,7 +38,7 @@ namespace Semmle.Extraction.CIL.Entities this.elementType = elementType; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('&'); @@ -54,7 +54,7 @@ namespace Semmle.Extraction.CIL.Entities this.signature = signature; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { FunctionPointerType.WriteName( trapFile.Write, @@ -84,7 +84,7 @@ namespace Semmle.Extraction.CIL.Entities this.typeArguments = typeArguments; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { genericType.WriteId(trapFile, gc); trapFile.Write('<'); @@ -112,7 +112,7 @@ namespace Semmle.Extraction.CIL.Entities this.index = index; } - public void WriteId(TextWriter trapFile, GenericContext outerGc) + public void WriteId(TextWriter trapFile, IGenericContext outerGc) { if (!ReferenceEquals(innerGc, outerGc) && innerGc is Method method) { @@ -132,7 +132,7 @@ namespace Semmle.Extraction.CIL.Entities this.index = index; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { trapFile.Write("T!"); trapFile.Write(index); @@ -158,7 +158,7 @@ namespace Semmle.Extraction.CIL.Entities this.isRequired = isRequired; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { unmodifiedType.WriteId(trapFile, gc); trapFile.Write(isRequired ? " modreq(" : " modopt("); @@ -186,7 +186,7 @@ namespace Semmle.Extraction.CIL.Entities this.elementType = elementType; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('*'); @@ -207,7 +207,7 @@ namespace Semmle.Extraction.CIL.Entities this.typeCode = typeCode; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { trapFile.Write(typeCode.Id()); } @@ -227,7 +227,7 @@ namespace Semmle.Extraction.CIL.Entities this.elementType = elementType; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write("[]"); @@ -248,7 +248,7 @@ namespace Semmle.Extraction.CIL.Entities this.handle = handle; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { var type = (Type)gc.Cx.Create(handle); type.WriteId(trapFile); @@ -269,7 +269,7 @@ namespace Semmle.Extraction.CIL.Entities this.handle = handle; } - public void WriteId(TextWriter trapFile, GenericContext gc) + public void WriteId(TextWriter trapFile, IGenericContext gc) { var type = (Type)gc.Cx.Create(handle); type.WriteId(trapFile); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index edeb1a54136..2df850f5ce9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -198,7 +198,7 @@ namespace Semmle.Extraction.CIL.Entities public sealed override IEnumerable MethodParameters => Enumerable.Empty(); - public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) => + public static Type DecodeType(IGenericContext gc, TypeSpecificationHandle handle) => gc.Cx.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Cx.TypeSignatureDecoder, gc); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs index a7b7a006af6..43e261de75a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs @@ -8,10 +8,13 @@ namespace Semmle.Extraction.CIL.Entities /// /// Base class for all type containers (namespaces, types, methods). /// - public abstract class TypeContainer : GenericContext, IExtractedEntity + public abstract class TypeContainer : IGenericContext, IExtractedEntity { - protected TypeContainer(Context cx) : base(cx) + public Context Cx { get; } + + protected TypeContainer(Context cx) { + Cx = cx; } public virtual Label Label { get; set; } @@ -42,5 +45,8 @@ namespace Semmle.Extraction.CIL.Entities } TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public abstract IEnumerable MethodParameters { get; } + public abstract IEnumerable TypeParameters { get; } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs index 7c8d2222fa5..fd18374ed2d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeParameter.cs @@ -9,9 +9,9 @@ namespace Semmle.Extraction.CIL.Entities { internal abstract class TypeParameter : Type { - protected readonly GenericContext gc; + protected readonly IGenericContext gc; - protected TypeParameter(GenericContext gc) : base(gc.Cx) + protected TypeParameter(IGenericContext gc) : base(gc.Cx) { this.gc = gc; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs index 2ec82226d55..4417becc58d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeSignatureDecoder.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities /// /// Decodes a type signature and produces a Type, for use by DecodeSignature() and friends. /// - public class TypeSignatureDecoder : ISignatureTypeProvider + public class TypeSignatureDecoder : ISignatureTypeProvider { private readonly Context cx; @@ -23,22 +23,22 @@ namespace Semmle.Extraction.CIL.Entities Type IConstructedTypeProvider.GetByReferenceType(Type elementType) => new ByRefType(cx, elementType); - Type ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => + Type ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => cx.Populate(new FunctionPointerType(cx, signature)); Type IConstructedTypeProvider.GetGenericInstantiation(Type genericType, ImmutableArray typeArguments) => genericType.Construct(typeArguments); - Type ISignatureTypeProvider.GetGenericMethodParameter(GenericContext genericContext, int index) => + Type ISignatureTypeProvider.GetGenericMethodParameter(IGenericContext genericContext, int index) => genericContext.MethodParameters.ElementAt(index); - Type ISignatureTypeProvider.GetGenericTypeParameter(GenericContext genericContext, int index) => + Type ISignatureTypeProvider.GetGenericTypeParameter(IGenericContext genericContext, int index) => genericContext.TypeParameters.ElementAt(index); - Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => + Type ISignatureTypeProvider.GetModifiedType(Type modifier, Type unmodifiedType, bool isRequired) => new ModifiedType(cx, unmodifiedType, modifier, isRequired); - Type ISignatureTypeProvider.GetPinnedType(Type elementType) => elementType; + Type ISignatureTypeProvider.GetPinnedType(Type elementType) => elementType; Type IConstructedTypeProvider.GetPointerType(Type elementType) => cx.Populate(new PointerType(cx, elementType)); @@ -54,7 +54,7 @@ namespace Semmle.Extraction.CIL.Entities Type ISimpleTypeProvider.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) => (Type)cx.Create(handle); - Type ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, GenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => + Type ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, IGenericContext genericContext, TypeSpecificationHandle handle, byte rawTypeKind) => throw new NotImplementedException(); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs b/csharp/extractor/Semmle.Extraction.CIL/IGenericContext.cs similarity index 59% rename from csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs rename to csharp/extractor/Semmle.Extraction.CIL/IGenericContext.cs index 1e9aa21e399..21c69f7aeb4 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/GenericContext.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/IGenericContext.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace Semmle.Extraction.CIL { @@ -7,24 +6,19 @@ namespace Semmle.Extraction.CIL /// When we decode a type/method signature, we need access to /// generic parameters. /// - public abstract class GenericContext + public interface IGenericContext { - public Context Cx { get; } - - protected GenericContext(Context cx) - { - this.Cx = cx; - } + Context Cx { get; } /// /// The list of generic type parameters/arguments, including type parameters/arguments of /// containing types. /// - public abstract IEnumerable TypeParameters { get; } + IEnumerable TypeParameters { get; } /// /// The list of generic method parameters/arguments. /// - public abstract IEnumerable MethodParameters { get; } + IEnumerable MethodParameters { get; } } } From 67caf3cad0587223f9eae289f54ed66f12771dfb Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 11:27:31 +0100 Subject: [PATCH 384/429] Remove redundant IEntity implemented interface declaration and explit interface member implemenration --- csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs | 2 +- .../Semmle.Extraction.CIL/Entities/Instruction.cs | 7 +------ .../Semmle.Extraction.CIL/Entities/TypeContainer.cs | 5 ++--- .../extractor/Semmle.Extraction.CIL/ExtractionProduct.cs | 4 ++-- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs index 670b24b4d86..a195a7432c7 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs @@ -61,7 +61,7 @@ namespace Semmle.Extraction.CIL.Entities cx2.Populate(this); } - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; public abstract IEnumerable TypeParameters { get; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 75d0aab454a..033010e18a3 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL.Entities /// /// A CIL instruction. /// - internal class Instruction : UnlabelledEntity, IEntity + internal class Instruction : UnlabelledEntity { /// /// The additional data following the opcode, if any. @@ -289,11 +289,6 @@ namespace Semmle.Extraction.CIL.Entities } } - Label IEntity.Label - { - get; set; - } - private readonly byte[] data; private int PayloadSize => payloadSizes[(int)PayloadType]; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs index 43e261de75a..66ee54ddc8d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs @@ -31,8 +31,6 @@ namespace Semmle.Extraction.CIL.Entities public abstract string IdSuffix { get; } - Location IEntity.ReportingLocation => throw new NotImplementedException(); - public void Extract(Context cx2) { cx2.Populate(this); } public abstract IEnumerable Contents { get; } @@ -44,7 +42,8 @@ namespace Semmle.Extraction.CIL.Entities return writer.ToString(); } - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public Location ReportingLocation => throw new NotImplementedException(); public abstract IEnumerable MethodParameters { get; } public abstract IEnumerable TypeParameters { get; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs b/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs index 52415af9349..62aaad0d8e5 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs @@ -71,7 +71,7 @@ namespace Semmle.Extraction.CIL cx.Cx.AddFreshLabel(this); } - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; } /// @@ -115,7 +115,7 @@ namespace Semmle.Extraction.CIL return writer.ToString(); } - TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel; + public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; } /// From e7853cc3a052ecdc9d645b95d05ef2c7dcb6e3c6 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 11:47:56 +0100 Subject: [PATCH 385/429] Simplify TypeContainer class --- .../Entities/TypeContainer.cs | 35 ++----------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs index 66ee54ddc8d..d8058593277 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs @@ -8,43 +8,12 @@ namespace Semmle.Extraction.CIL.Entities /// /// Base class for all type containers (namespaces, types, methods). /// - public abstract class TypeContainer : IGenericContext, IExtractedEntity + public abstract class TypeContainer : LabelledEntity, IGenericContext { - public Context Cx { get; } - - protected TypeContainer(Context cx) + protected TypeContainer(Context cx) : base(cx) { - Cx = cx; } - public virtual Label Label { get; set; } - - public abstract void WriteId(TextWriter trapFile); - - public void WriteQuotedId(TextWriter trapFile) - { - trapFile.Write("@\""); - WriteId(trapFile); - trapFile.Write(IdSuffix); - trapFile.Write('\"'); - } - - public abstract string IdSuffix { get; } - - public void Extract(Context cx2) { cx2.Populate(this); } - - public abstract IEnumerable Contents { get; } - - public override string ToString() - { - using var writer = new StringWriter(); - WriteQuotedId(writer); - return writer.ToString(); - } - - public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - public Location ReportingLocation => throw new NotImplementedException(); - public abstract IEnumerable MethodParameters { get; } public abstract IEnumerable TypeParameters { get; } } From 67289a498fb1783d5f2e8d2fa736223dcf1035d1 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 13:52:38 +0100 Subject: [PATCH 386/429] Share entity base classes between CIL and source extraction --- .../Entities/Assembly.cs | 3 +- .../Entities/Attribute.cs | 6 +- .../Entities/Base/IExtractedEntity.cs | 16 ++ .../Entities/Base/IExtractionProduct.cs | 24 +++ .../{ => Entities/Base}/IGenericContext.cs | 0 .../Entities/Base/LabelledEntity.cs | 39 ++++ .../Entities/Base/Tuple.cs | 22 +++ .../Entities/Base/UnlabelledEntity.cs | 31 +++ .../Semmle.Extraction.CIL/Entities/Event.cs | 3 +- .../Semmle.Extraction.CIL/Entities/Field.cs | 33 +--- .../Semmle.Extraction.CIL/Entities/File.cs | 3 +- .../Semmle.Extraction.CIL/Entities/Folder.cs | 3 +- .../Entities/LocalVariable.cs | 3 +- .../Semmle.Extraction.CIL/Entities/Method.cs | 3 +- .../Entities/Namespace.cs | 4 +- .../Entities/Parameter.cs | 17 +- .../Entities/Property.cs | 2 +- .../Entities/SourceLocation.cs | 3 +- .../Semmle.Extraction.CIL/Entities/Type.cs | 8 +- .../ExtractionProduct.cs | 140 -------------- .../extractor/Semmle.Extraction.CIL/Tuples.cs | 8 +- .../Entities/Compilations/Diagnostic.cs | 2 +- .../Entities/Expression.cs | 12 +- .../Entities/Expression`1.cs | 2 +- .../Entities/Expressions/Access.cs | 4 +- .../Entities/Expressions/ArrayCreation.cs | 14 +- .../Entities/Expressions/Assignment.cs | 18 +- .../Entities/Expressions/Await.cs | 2 +- .../Entities/Expressions/Binary.cs | 4 +- .../Entities/Expressions/Cast.cs | 6 +- .../Entities/Expressions/Checked.cs | 2 +- .../Entities/Expressions/Conditional.cs | 6 +- .../Entities/Expressions/Default.cs | 2 +- .../Entities/Expressions/ElementAccess.cs | 10 +- .../Entities/Expressions/ImplicitCast.cs | 8 +- .../Entities/Expressions/Initializer.cs | 38 ++-- .../Expressions/InterpolatedString.cs | 4 +- .../Entities/Expressions/Invocation.cs | 22 +-- .../Entities/Expressions/IsPattern.cs | 4 +- .../Entities/Expressions/Lambda.cs | 18 +- .../Entities/Expressions/MakeRef.cs | 2 +- .../Entities/Expressions/MemberAccess.cs | 6 +- .../ObjectCreation/AnonymousObjectCreation.cs | 20 +- .../ObjectCreation/BaseObjectCreation.cs | 16 +- .../ObjectCreation/ExplicitObjectCreation.cs | 2 +- .../Expressions/PointerMemberAccess.cs | 2 +- .../Entities/Expressions/PostfixUnary.cs | 2 +- .../Entities/Expressions/RangeExpression.cs | 4 +- .../Entities/Expressions/Ref.cs | 2 +- .../Entities/Expressions/RefType.cs | 2 +- .../Entities/Expressions/RefValue.cs | 4 +- .../Entities/Expressions/Sizeof.cs | 2 +- .../Entities/Expressions/Switch.cs | 4 +- .../Entities/Expressions/Throw.cs | 2 +- .../Entities/Expressions/Tuple.cs | 2 +- .../Entities/Expressions/TypeAccess.cs | 8 +- .../Entities/Expressions/TypeOf.cs | 2 +- .../Entities/Expressions/Unary.cs | 2 +- .../Entities/Expressions/Unchecked.cs | 2 +- .../PreprocessorDirectives/ElifDirective.cs | 2 +- .../PreprocessorDirectives/IfDirective.cs | 2 +- .../PreprocessorDirectives/LineDirective.cs | 2 +- .../PragmaChecksumDirective.cs | 2 +- .../PreprocessorDirective.cs | 6 +- .../Entities/Property.cs | 2 +- .../Entities/Statements/Block.cs | 2 +- .../Entities/Statements/Case.cs | 8 +- .../Entities/Statements/Catch.cs | 12 +- .../Entities/Statements/Checked.cs | 2 +- .../Entities/Statements/Do.cs | 4 +- .../Statements/ExpressionStatement.cs | 4 +- .../Entities/Statements/Fixed.cs | 4 +- .../Entities/Statements/For.cs | 10 +- .../Entities/Statements/ForEach.cs | 28 +-- .../Entities/Statements/Goto.cs | 4 +- .../Entities/Statements/If.cs | 6 +- .../Entities/Statements/Labeled.cs | 2 +- .../Entities/Statements/LocalDeclaration.cs | 4 +- .../Entities/Statements/LocalFunction.cs | 4 +- .../Entities/Statements/Lock.cs | 4 +- .../Entities/Statements/Return.cs | 2 +- .../Entities/Statements/Switch.cs | 6 +- .../Entities/Statements/Throw.cs | 2 +- .../Entities/Statements/Try.cs | 6 +- .../Entities/Statements/Unchecked.cs | 2 +- .../Entities/Statements/Unsafe.cs | 2 +- .../Entities/Statements/Using.cs | 6 +- .../Entities/Statements/While.cs | 4 +- .../Entities/Statements/Yield.cs | 2 +- .../Entities/TypeMention.cs | 22 +-- .../Entities/Types/Type.cs | 1 + .../Entities/UsingDirective.cs | 14 +- csharp/extractor/Semmle.Extraction/Context.cs | 26 +-- .../Base/CachedEntity`1.cs} | 59 +++--- .../Semmle.Extraction/Entities/Base/Entity.cs | 64 +++++++ .../Entities/Base/FreshEntity.cs | 38 ++++ .../Entities/Base/ICachedEntityFactory.cs | 14 ++ .../Base/ICachedEntityFactoryExtensions.cs | 35 ++++ .../Entities/Base/IEntity.cs | 53 ++++++ .../Entities/Base/LabelledEntity.cs | 18 ++ .../Entities/Base/UnlabelledEntity.cs | 22 +++ .../Entities/ExtractionError.cs | 2 +- .../Entities/SourceLocation.cs | 2 +- csharp/extractor/Semmle.Extraction/Entity.cs | 177 ------------------ .../Semmle.Extraction/FreshEntity.cs | 59 ------ .../Semmle.Extraction/TrapStackBehaviour.cs | 28 +++ 106 files changed, 705 insertions(+), 710 deletions(-) create mode 100644 csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs rename csharp/extractor/Semmle.Extraction.CIL/{ => Entities/Base}/IGenericContext.cs (100%) create mode 100644 csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs create mode 100644 csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs delete mode 100644 csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs rename csharp/extractor/Semmle.Extraction/{Symbol.cs => Entities/Base/CachedEntity`1.cs} (63%) create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/Entity.cs create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/FreshEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/ICachedEntityFactory.cs create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/ICachedEntityFactoryExtensions.cs create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/IEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/LabelledEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction/Entities/Base/UnlabelledEntity.cs delete mode 100644 csharp/extractor/Semmle.Extraction/Entity.cs delete mode 100644 csharp/extractor/Semmle.Extraction/FreshEntity.cs create mode 100644 csharp/extractor/Semmle.Extraction/TrapStackBehaviour.cs diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs index 5c0a834909c..ba332b2db97 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs @@ -40,6 +40,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(FullName); trapFile.Write("#file:///"); trapFile.Write(Cx.AssemblyPath.Replace("\\", "/")); + trapFile.Write(";assembly"); } public override bool Equals(object? obj) @@ -49,8 +50,6 @@ namespace Semmle.Extraction.CIL.Entities public override int GetHashCode() => 7 * file.GetHashCode(); - public override string IdSuffix => ";assembly"; - private string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName; public override IEnumerable Contents diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs index c862bc3fc4e..d79215f0adf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs @@ -12,9 +12,9 @@ namespace Semmle.Extraction.CIL.Entities { private readonly CustomAttributeHandle handle; private readonly CustomAttribute attrib; - private readonly IEntity @object; + private readonly IExtractedEntity @object; - public Attribute(Context cx, IEntity @object, CustomAttributeHandle handle) : base(cx) + public Attribute(Context cx, IExtractedEntity @object, CustomAttributeHandle handle) : base(cx) { attrib = cx.MdReader.GetCustomAttribute(handle); this.handle = handle; @@ -80,7 +80,7 @@ namespace Semmle.Extraction.CIL.Entities return value?.ToString() ?? "null"; } - public static IEnumerable Populate(Context cx, IEntity @object, CustomAttributeHandleCollection attributes) + public static IEnumerable Populate(Context cx, IExtractedEntity @object, CustomAttributeHandleCollection attributes) { foreach (var attrib in attributes) { diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs new file mode 100644 index 00000000000..080227a63b9 --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractedEntity.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace Semmle.Extraction.CIL +{ + /// + /// A CIL entity which has been extracted. + /// + public interface IExtractedEntity : IExtractionProduct, IEntity + { + /// + /// The contents of the entity. + /// + + IEnumerable Contents { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs new file mode 100644 index 00000000000..6383d7e1b4c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IExtractionProduct.cs @@ -0,0 +1,24 @@ +namespace Semmle.Extraction.CIL +{ + /// + /// Something that is extracted from an entity. + /// + /// + /// + /// The extraction algorithm proceeds as follows: + /// - Construct entity + /// - Call Extract() + /// - IExtractedEntity check if already extracted + /// - Enumerate Contents to produce more extraction products + /// - Extract these until there is nothing left to extract + /// + public interface IExtractionProduct + { + /// + /// Perform further extraction/population of this item as necessary. + /// + /// + /// The extraction context. + void Extract(Context cx); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/IGenericContext.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IGenericContext.cs similarity index 100% rename from csharp/extractor/Semmle.Extraction.CIL/IGenericContext.cs rename to csharp/extractor/Semmle.Extraction.CIL/Entities/Base/IGenericContext.cs diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs new file mode 100644 index 00000000000..a66ecbb1fab --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/LabelledEntity.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Semmle.Extraction.CIL +{ + /// + /// An entity that needs to be populated during extraction. + /// This assigns a key and optionally extracts its contents. + /// + public abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity + { + // todo: with .NET 5 this can override the base context, and change the return type. + public Context Cx { get; } + + protected LabelledEntity(Context cx) : base(cx.Cx) + { + this.Cx = cx; + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); + + public void Extract(Context cx2) + { + cx2.Populate(this); + } + + public override string ToString() + { + using var writer = new StringWriter(); + WriteQuotedId(writer); + return writer.ToString(); + } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public abstract IEnumerable Contents { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs new file mode 100644 index 00000000000..5657f072c9c --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/Tuple.cs @@ -0,0 +1,22 @@ +namespace Semmle.Extraction.CIL +{ + /// + /// A tuple that is an extraction product. + /// + internal class Tuple : IExtractionProduct + { + private readonly Extraction.Tuple tuple; + + public Tuple(string name, params object[] args) + { + tuple = new Extraction.Tuple(name, args); + } + + public void Extract(Context cx) + { + cx.Cx.Emit(tuple); + } + + public override string ToString() => tuple.ToString(); + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs new file mode 100644 index 00000000000..d8c18d291eb --- /dev/null +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Base/UnlabelledEntity.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace Semmle.Extraction.CIL +{ + /// + /// An entity that has contents to extract. There is no need to populate + /// a key as it's done in the contructor. + /// + public abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity + { + // todo: with .NET 5 this can override the base context, and change the return type. + public Context Cx { get; } + + protected UnlabelledEntity(Context cx) : base(cx.Cx) + { + Cx = cx; + } + + public override Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); + + public void Extract(Context cx2) + { + cx2.Extract(this); + } + + public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; + + public abstract IEnumerable Contents { get; } + } +} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs index e2e27484a4c..a6ca9364e0f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs @@ -25,10 +25,9 @@ namespace Semmle.Extraction.CIL.Entities parent.WriteId(trapFile); trapFile.Write('.'); trapFile.Write(Cx.ShortName(ed.Name)); + trapFile.Write(";cil-event"); } - public override string IdSuffix => ";cil-event"; - public override bool Equals(object? obj) { return obj is Event e && handle.Equals(e.handle); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs index a195a7432c7..8decef24128 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs @@ -8,41 +8,27 @@ namespace Semmle.Extraction.CIL.Entities /// /// An entity representing a field. /// - internal abstract class Field : IGenericContext, IMember, ICustomModifierReceiver + internal abstract class Field : LabelledEntity, IGenericContext, IMember, ICustomModifierReceiver { - protected Field(Context cx) + protected Field(Context cx) : base(cx) { - Cx = cx; } - public Label Label { get; set; } - - public void WriteId(TextWriter trapFile) + public override void WriteId(TextWriter trapFile) { trapFile.WriteSubId(DeclaringType); trapFile.Write('.'); trapFile.Write(Name); + trapFile.Write(";cil-field"); } - public void WriteQuotedId(TextWriter trapFile) - { - trapFile.Write("@\""); - WriteId(trapFile); - trapFile.Write(idSuffix); - trapFile.Write('\"'); - } - - private const string idSuffix = ";cil-field"; - public abstract string Name { get; } public abstract Type DeclaringType { get; } - public Location ReportingLocation => throw new NotImplementedException(); - public abstract Type Type { get; } - public virtual IEnumerable Contents + public override IEnumerable Contents { get { @@ -56,17 +42,8 @@ namespace Semmle.Extraction.CIL.Entities } } - public void Extract(Context cx2) - { - cx2.Populate(this); - } - - public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - public abstract IEnumerable TypeParameters { get; } public abstract IEnumerable MethodParameters { get; } - - public Context Cx { get; } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs index d5cb10a43db..4b612ae86af 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs @@ -17,6 +17,7 @@ namespace Semmle.Extraction.CIL.Entities public override void WriteId(TextWriter trapFile) { trapFile.Write(TransformedPath.DatabaseId); + trapFile.Write(";sourcefile"); } public override bool Equals(object? obj) @@ -39,7 +40,5 @@ namespace Semmle.Extraction.CIL.Entities yield return Tuples.files(this, TransformedPath.Value, TransformedPath.NameWithoutExtension, TransformedPath.Extension); } } - - public override string IdSuffix => ";sourcefile"; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs index 6121792600a..2294a525e4b 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs @@ -15,10 +15,9 @@ namespace Semmle.Extraction.CIL.Entities public override void WriteId(TextWriter trapFile) { trapFile.Write(transformedPath.DatabaseId); + trapFile.Write(";folder"); } - public override string IdSuffix => ";folder"; - public override IEnumerable Contents { get diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs index d96c430f3c9..5d7a00c64c9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/LocalVariable.cs @@ -21,10 +21,9 @@ namespace Semmle.Extraction.CIL.Entities trapFile.WriteSubId(method); trapFile.Write('_'); trapFile.Write(index); + trapFile.Write(";cil-local"); } - public override string IdSuffix => ";cil-local"; - public override IEnumerable Contents { get diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index d1302837c16..e2887963edf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -62,10 +62,9 @@ namespace Semmle.Extraction.CIL.Entities param.WriteId(trapFile, this); } trapFile.Write(')'); + trapFile.Write(";cil-method"); } - public override string IdSuffix => ";cil-method"; - protected IEnumerable PopulateFlags { get diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs index e916fd0020f..5f909b7b336 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs @@ -14,9 +14,6 @@ namespace Semmle.Extraction.CIL.Entities public bool IsGlobalNamespace => ParentNamespace is null; - public override string IdSuffix => ";namespace"; - - public override void WriteId(TextWriter trapFile) { if (ParentNamespace != null && !ParentNamespace.IsGlobalNamespace) @@ -25,6 +22,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write('.'); } trapFile.Write(Name); + trapFile.Write(";namespace"); } public override bool Equals(object? obj) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs index 90452fe9265..9cf96412309 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs @@ -8,41 +8,40 @@ namespace Semmle.Extraction.CIL.Entities /// internal sealed class Parameter : LabelledEntity { - private readonly IParameterizable method; + private readonly IParameterizable parameterizable; private readonly int index; private readonly Type type; - public Parameter(Context cx, IParameterizable m, int i, Type t) : base(cx) + public Parameter(Context cx, IParameterizable p, int i, Type t) : base(cx) { - method = m; + parameterizable = p; index = i; type = t; } public override void WriteId(TextWriter trapFile) { - trapFile.WriteSubId(method); + trapFile.WriteSubId(parameterizable); trapFile.Write('_'); trapFile.Write(index); + trapFile.Write(";cil-parameter"); } public override bool Equals(object? obj) { - return obj is Parameter param && method.Equals(param.method) && index == param.index; + return obj is Parameter param && parameterizable.Equals(param.parameterizable) && index == param.index; } public override int GetHashCode() { - return 23 * method.GetHashCode() + index; + return 23 * parameterizable.GetHashCode() + index; } - public override string IdSuffix => ";cil-parameter"; - public override IEnumerable Contents { get { - yield return Tuples.cil_parameter(this, method, index, type); + yield return Tuples.cil_parameter(this, parameterizable, index, type); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs index a6c864a8cb6..e605468827a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs @@ -13,7 +13,6 @@ namespace Semmle.Extraction.CIL.Entities private readonly Handle handle; private readonly Type type; private readonly PropertyDefinition pd; - public override string IdSuffix => ";cil-property"; private readonly IGenericContext gc; public Property(IGenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx) @@ -38,6 +37,7 @@ namespace Semmle.Extraction.CIL.Entities param.WriteId(trapFile, gc); } trapFile.Write(")"); + trapFile.Write(";cil-property"); } public override bool Equals(object? obj) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs index f0f1667bca2..318cac14930 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs @@ -26,6 +26,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(location.EndLine); trapFile.Write(','); trapFile.Write(location.EndColumn); + trapFile.Write(";sourcelocation"); } public override bool Equals(object? obj) @@ -43,7 +44,5 @@ namespace Semmle.Extraction.CIL.Entities yield return Tuples.locations_default(this, file, location.StartLine, location.StartColumn, location.EndLine, location.EndColumn); } } - - public override string IdSuffix => ";sourcelocation"; } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index 2df850f5ce9..9f78c5066e0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -11,7 +11,6 @@ namespace Semmle.Extraction.CIL.Entities /// public abstract class Type : TypeContainer, IMember { - public override string IdSuffix => ";cil-type"; internal const string AssemblyTypeNameSeparator = "::"; internal const string PrimitiveTypePrefix = "builtin" + AssemblyTypeNameSeparator + "System."; @@ -46,7 +45,12 @@ namespace Semmle.Extraction.CIL.Entities /// public abstract void WriteId(TextWriter trapFile, bool inContext); - public sealed override void WriteId(TextWriter trapFile) => WriteId(trapFile, false); + public sealed override void WriteId(TextWriter trapFile) + { + WriteId(trapFile, false); + trapFile.Write(";cil-type"); + } + /// /// Returns the friendly qualified name of types, such as diff --git a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs b/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs deleted file mode 100644 index 62aaad0d8e5..00000000000 --- a/csharp/extractor/Semmle.Extraction.CIL/ExtractionProduct.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Semmle.Extraction.CIL -{ - /// - /// Something that is extracted from an entity. - /// - /// - /// - /// The extraction algorithm proceeds as follows: - /// - Construct entity - /// - Call Extract() - /// - IExtractedEntity check if already extracted - /// - Enumerate Contents to produce more extraction products - /// - Extract these until there is nothing left to extract - /// - public interface IExtractionProduct - { - /// - /// Perform further extraction/population of this item as necessary. - /// - /// - /// The extraction context. - void Extract(Context cx); - } - - /// - /// An entity which has been extracted. - /// - public interface IExtractedEntity : IEntity, IExtractionProduct - { - /// - /// The contents of the entity. - /// - IEnumerable Contents { get; } - } - - /// - /// An entity that has contents to extract. There is no need to populate - /// a key as it's done in the contructor. - /// - public abstract class UnlabelledEntity : IExtractedEntity - { - public abstract IEnumerable Contents { get; } - public Label Label { get; set; } - - public void WriteId(System.IO.TextWriter trapFile) - { - trapFile.Write('*'); - } - - public void WriteQuotedId(TextWriter trapFile) - { - WriteId(trapFile); - } - - public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); - - public virtual void Extract(Context cx2) - { - cx2.Extract(this); - } - - public Context Cx { get; } - - protected UnlabelledEntity(Context cx) - { - this.Cx = cx; - cx.Cx.AddFreshLabel(this); - } - - public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - } - - /// - /// An entity that needs to be populated during extraction. - /// This assigns a key and optionally extracts its contents. - /// - public abstract class LabelledEntity : IExtractedEntity - { - public abstract IEnumerable Contents { get; } - public Label Label { get; set; } - public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException(); - - public abstract void WriteId(System.IO.TextWriter trapFile); - - public abstract string IdSuffix { get; } - - public void WriteQuotedId(TextWriter trapFile) - { - trapFile.Write("@\""); - WriteId(trapFile); - trapFile.Write(IdSuffix); - trapFile.Write('\"'); - } - - public void Extract(Context cx2) - { - cx2.Populate(this); - } - - public Context Cx { get; } - - protected LabelledEntity(Context cx) - { - this.Cx = cx; - } - - public override string ToString() - { - using var writer = new StringWriter(); - WriteQuotedId(writer); - return writer.ToString(); - } - - public TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - } - - /// - /// A tuple that is an extraction product. - /// - internal class Tuple : IExtractionProduct - { - private readonly Extraction.Tuple tuple; - - public Tuple(string name, params object[] args) - { - tuple = new Extraction.Tuple(name, args); - } - - public void Extract(Context cx) - { - cx.Cx.Emit(tuple); - } - - public override string ToString() => tuple.ToString(); - } -} diff --git a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs index 0ae92386c3e..c8ed3445c6f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Tuples.cs @@ -14,10 +14,10 @@ namespace Semmle.Extraction.CIL internal static Tuple cil_adder(Event member, Method method) => new Tuple("cil_adder", member, method); - internal static Tuple cil_access(Instruction i, IEntity m) => + internal static Tuple cil_access(Instruction i, IExtractedEntity m) => new Tuple("cil_access", i, m); - internal static Tuple cil_attribute(Attribute attribute, IEntity @object, Method constructor) => + internal static Tuple cil_attribute(Attribute attribute, IExtractedEntity @object, Method constructor) => new Tuple("cil_attribute", attribute, @object, constructor); internal static Tuple cil_attribute_named_argument(Attribute attribute, string name, string value) => @@ -197,7 +197,7 @@ namespace Semmle.Extraction.CIL internal static Tuple cil_custom_modifiers(ICustomModifierReceiver receiver, Type modifier, bool isRequired) => new Tuple("cil_custom_modifiers", receiver, modifier, isRequired ? 1 : 0); - internal static Tuple cil_type_annotation(IEntity receiver, TypeAnnotation annotation) => + internal static Tuple cil_type_annotation(IExtractedEntity receiver, TypeAnnotation annotation) => new Tuple("cil_type_annotation", receiver, (int)annotation); internal static Tuple containerparent(Folder parent, IFileOrFolder child) => @@ -215,7 +215,7 @@ namespace Semmle.Extraction.CIL internal static Tuple locations_default(PdbSourceLocation label, File file, int startLine, int startCol, int endLine, int endCol) => new Tuple("locations_default", label, file, startLine, startCol, endLine, endCol); - internal static Tuple metadata_handle(IEntity entity, Assembly assembly, int handleValue) => + internal static Tuple metadata_handle(IExtractedEntity entity, Assembly assembly, int handleValue) => new Tuple("metadata_handle", entity, assembly, handleValue); internal static Tuple namespaces(Namespace ns, string name) => diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs index ddf53d6bbe1..def6edbf5ad 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Compilations/Diagnostic.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities protected override void Populate(TextWriter trapFile) { trapFile.diagnostics(this, (int)diagnostic.Severity, diagnostic.Id, diagnostic.Descriptor.Title.ToString(), - diagnostic.GetMessage(), cx.CreateLocation(diagnostic.Location)); + diagnostic.GetMessage(), Context.CreateLocation(diagnostic.Location)); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index e343414a4cb..e96410fb8f5 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities protected sealed override void Populate(TextWriter trapFile) { - var type = Type.HasValue ? Entities.Type.Create(cx, Type.Value) : NullType.Create(cx); + var type = Type.HasValue ? Entities.Type.Create(Context, Type.Value) : NullType.Create(Context); trapFile.expressions(this, Kind, type.TypeRef); if (info.Parent.IsTopLevelParent) trapFile.expr_parent_top_level(this, info.Child, info.Parent); @@ -39,7 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities if (Type.HasValue && !Type.Value.HasObliviousNullability()) { - var n = NullabilityEntity.Create(cx, Nullability.Create(Type.Value)); + var n = NullabilityEntity.Create(Context, Nullability.Create(Type.Value)); trapFile.type_nullability(this, n); } @@ -170,10 +170,10 @@ namespace Semmle.Extraction.CSharp.Entities /// The expression. public void OperatorCall(TextWriter trapFile, ExpressionSyntax node) { - var @operator = cx.GetSymbolInfo(node); + var @operator = Context.GetSymbolInfo(node); if (@operator.Symbol is IMethodSymbol method) { - var callType = GetCallType(cx, node); + var callType = GetCallType(Context, node); if (callType == CallType.Dynamic) { UserOperator.OperatorSymbol(method.Name, out var operatorName); @@ -181,7 +181,7 @@ namespace Semmle.Extraction.CSharp.Entities return; } - trapFile.expr_call(this, Method.Create(cx, method)); + trapFile.expr_call(this, Method.Create(Context, method)); } } @@ -267,7 +267,7 @@ namespace Semmle.Extraction.CSharp.Entities private void PopulateArgument(TextWriter trapFile, ArgumentSyntax arg, int child) { - var expr = Create(cx, arg.Expression, this, child); + var expr = Create(Context, arg.Expression, this, child); int mode; switch (arg.RefOrOutKeyword.Kind()) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs index c16f0679c10..6c027076472 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression`1.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CSharp.Entities protected new Expression TryPopulate() { - cx.Try(Syntax, null, () => PopulateExpression(cx.TrapWriter.Writer)); + Context.Try(Syntax, null, () => PopulateExpression(Context.TrapWriter.Writer)); return this; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs index d4d4c86c507..8ef72f8085c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Access.cs @@ -47,12 +47,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (!(target is null)) { - cx.TrapWriter.Writer.expr_access(this, target); + Context.TrapWriter.Writer.expr_access(this, target); } if (implicitThis && !symbol.IsStatic) { - This.CreateImplicit(cx, symbol.ContainingType, Location, this, -1); + This.CreateImplicit(Context, symbol.ContainingType, Location, this, -1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs index ea818862d80..3d6d3b95722 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs @@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (TypeSyntax is null) { - cx.ModelError(Syntax, "Array has unexpected type syntax"); + Context.ModelError(Syntax, "Array has unexpected type syntax"); } var firstLevelSizes = TypeSyntax.RankSpecifiers.First()?.Sizes ?? SyntaxFactory.SeparatedList(); @@ -44,20 +44,20 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { for (var sizeIndex = 0; sizeIndex < firstLevelSizes.Count; sizeIndex++) { - Create(cx, firstLevelSizes[sizeIndex], this, sizeIndex); + Create(Context, firstLevelSizes[sizeIndex], this, sizeIndex); } explicitlySized = true; } if (!(Initializer is null)) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Initializer, this, InitializerIndex)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Initializer, this, InitializerIndex)); } if (explicitlySized) trapFile.explicitly_sized_array_creation(this); - TypeMention.Create(cx, TypeSyntax, this, Type); + TypeMention.Create(Context, TypeSyntax, this, Type); } private void SetArraySizes(InitializerExpressionSyntax initializer, int rank) @@ -69,7 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions return; } - Literal.CreateGenerated(cx, this, level, cx.Compilation.GetSpecialType(SpecialType.System_Int32), initializer.Expressions.Count, Location); + Literal.CreateGenerated(Context, this, level, Context.Compilation.GetSpecialType(SpecialType.System_Int32), initializer.Expressions.Count, Location); initializer = initializer.Expressions.FirstOrDefault() as InitializerExpressionSyntax; } @@ -143,7 +143,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, InitializerIndex)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, InitializerIndex)); trapFile.implicitly_typed_array_creation(this); trapFile.stackalloc_array_creation(this); } @@ -159,7 +159,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (Syntax.Initializer != null) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, InitializerIndex)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, InitializerIndex)); } trapFile.implicitly_typed_array_creation(this); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs index f785ce65da3..3325c8075a3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs @@ -26,17 +26,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (operatorKind.HasValue) { // Convert assignment such as `a += b` into `a = a + b`. - var simpleAssignExpr = new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.SIMPLE_ASSIGN, this, 2, false, null)); - Create(cx, Syntax.Left, simpleAssignExpr, 1); - var opexpr = new Expression(new ExpressionInfo(cx, Type, Location, operatorKind.Value, simpleAssignExpr, 0, false, null)); - Create(cx, Syntax.Left, opexpr, 0); - Create(cx, Syntax.Right, opexpr, 1); + var simpleAssignExpr = new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.SIMPLE_ASSIGN, this, 2, false, null)); + Create(Context, Syntax.Left, simpleAssignExpr, 1); + var opexpr = new Expression(new ExpressionInfo(Context, Type, Location, operatorKind.Value, simpleAssignExpr, 0, false, null)); + Create(Context, Syntax.Left, opexpr, 0); + Create(Context, Syntax.Right, opexpr, 1); opexpr.OperatorCall(trapFile, Syntax); } else { - Create(cx, Syntax.Left, this, 1); - Create(cx, Syntax.Right, this, 0); + Create(Context, Syntax.Left, this, 1); + Create(Context, Syntax.Right, this, 0); if (Kind == ExprKind.ADD_EVENT || Kind == ExprKind.REMOVE_EVENT) { @@ -148,12 +148,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions case ExprKind.ASSIGN_COALESCE: return ExprKind.NULL_COALESCING; default: - cx.ModelError(Syntax, "Couldn't unfold assignment of type " + kind); + Context.ModelError(Syntax, "Couldn't unfold assignment of type " + kind); return ExprKind.UNKNOWN; } } } - public new CallType CallType => GetCallType(cx, Syntax); + public new CallType CallType => GetCallType(Context, Syntax); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs index 2f8726c8070..34088d9564a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Await.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs index 32ee3be5f73..74dcc9ff85f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs @@ -17,8 +17,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { OperatorCall(trapFile, Syntax); - CreateDeferred(cx, Syntax.Left, this, 0); - CreateDeferred(cx, Syntax.Right, this, 1); + CreateDeferred(Context, Syntax.Left, this, 0); + CreateDeferred(Context, Syntax.Right, this, 1); } private static ExprKind GetKind(Context cx, BinaryExpressionSyntax node) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs index 6f2551ec904..2afe7a9b37e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Cast.cs @@ -16,17 +16,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, ExpressionIndex); + Create(Context, Syntax.Expression, this, ExpressionIndex); if (Kind == ExprKind.CAST) { // Type cast - TypeAccess.Create(new ExpressionNodeInfo(cx, Syntax.Type, this, TypeAccessIndex)); + TypeAccess.Create(new ExpressionNodeInfo(Context, Syntax.Type, this, TypeAccessIndex)); } else { // Type conversion OperatorCall(trapFile, Syntax); - TypeMention.Create(cx, Syntax.Type, this, Type); + TypeMention.Create(Context, Syntax.Type, this, Type); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs index e6958c4511c..4be8b378937 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Checked.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs index bfa4a836feb..193c88b112a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Conditional.cs @@ -12,9 +12,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Condition, this, 0); - Create(cx, Syntax.WhenTrue, this, 1); - Create(cx, Syntax.WhenFalse, this, 2); + Create(Context, Syntax.Condition, this, 0); + Create(Context, Syntax.WhenTrue, this, 1); + Create(Context, Syntax.WhenFalse, this, 2); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs index 326516bba1b..9e1b42834b1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Default.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - TypeAccess.Create(cx, Syntax.Type, this, 0); + TypeAccess.Create(Context, Syntax.Type, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs index 59e573984fe..e860731ece3 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ElementAccess.cs @@ -22,22 +22,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (Kind == ExprKind.POINTER_INDIRECTION) { - var qualifierInfo = new ExpressionNodeInfo(cx, qualifier, this, 0); - var add = new Expression(new ExpressionInfo(cx, qualifierInfo.Type, Location, ExprKind.ADD, this, 0, false, null)); + var qualifierInfo = new ExpressionNodeInfo(Context, qualifier, this, 0); + var add = new Expression(new ExpressionInfo(Context, qualifierInfo.Type, Location, ExprKind.ADD, this, 0, false, null)); qualifierInfo.SetParent(add, 0); CreateFromNode(qualifierInfo); PopulateArguments(trapFile, argumentList, 1); } else { - Create(cx, qualifier, this, -1); + Create(Context, qualifier, this, -1); PopulateArguments(trapFile, argumentList, 0); - var symbolInfo = cx.GetSymbolInfo(base.Syntax); + var symbolInfo = Context.GetSymbolInfo(base.Syntax); if (symbolInfo.Symbol is IPropertySymbol indexer) { - trapFile.expr_access(this, Indexer.Create(cx, indexer)); + trapFile.expr_access(this, Indexer.Create(Context, indexer)); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs index eccead4a4de..96d8dec039a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions public ImplicitCast(ExpressionNodeInfo info) : base(new ExpressionInfo(info.Context, info.ConvertedType, info.Location, ExprKind.CAST, info.Parent, info.Child, true, info.ExprValue)) { - Expr = Factory.Create(new ExpressionNodeInfo(cx, info.Node, this, 0)); + Expr = Factory.Create(new ExpressionNodeInfo(Context, info.Node, this, 0)); } public ImplicitCast(ExpressionNodeInfo info, IMethodSymbol method) @@ -22,11 +22,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { Expr = Factory.Create(info.SetParent(this, 0)); - var target = Method.Create(cx, method); + var target = Method.Create(Context, method); if (target != null) - cx.TrapWriter.Writer.expr_call(this, target); + Context.TrapWriter.Writer.expr_call(this, target); else - cx.ModelError(info.Node, "Failed to resolve target for operator invocation"); + Context.ModelError(info.Node, "Failed to resolve target for operator invocation"); } /// diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs index 14fea3d4ce7..7e36d1ac789 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Initializer.cs @@ -26,12 +26,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (e.Kind() == SyntaxKind.ArrayInitializerExpression) { // Recursively create another array initializer - Create(new ExpressionNodeInfo(cx, (InitializerExpressionSyntax)e, this, child++)); + Create(new ExpressionNodeInfo(Context, (InitializerExpressionSyntax)e, this, child++)); } else { // Create the expression normally. - Create(cx, e, this, child++); + Create(Context, e, this, child++); } } } @@ -61,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - ArrayInitializer.Create(new ExpressionNodeInfo(cx, Syntax, this, -1)); + ArrayInitializer.Create(new ExpressionNodeInfo(Context, Syntax, this, -1)); trapFile.implicitly_typed_array_creation(this); } } @@ -81,9 +81,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { if (init is AssignmentExpressionSyntax assignment) { - var assignmentInfo = new ExpressionNodeInfo(cx, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); + var assignmentInfo = new ExpressionNodeInfo(Context, init, this, child++).SetKind(ExprKind.SIMPLE_ASSIGN); var assignmentEntity = new Expression(assignmentInfo); - var typeInfoRight = cx.GetTypeInfo(assignment.Right); + var typeInfoRight = Context.GetTypeInfo(assignment.Right); if (typeInfoRight.Type is null) // The type may be null for nested initializers such as // ```csharp @@ -92,15 +92,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions // In this case we take the type from the assignment // `As = { [0] = a }` instead typeInfoRight = assignmentInfo.TypeInfo; - CreateFromNode(new ExpressionNodeInfo(cx, assignment.Right, assignmentEntity, 0, typeInfoRight)); + CreateFromNode(new ExpressionNodeInfo(Context, assignment.Right, assignmentEntity, 0, typeInfoRight)); - var target = cx.GetSymbolInfo(assignment.Left); + var target = Context.GetSymbolInfo(assignment.Left); // If the target is null, then assume that this is an array initializer (of the form `[...] = ...`) var access = target.Symbol is null ? - new Expression(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : - Access.Create(new ExpressionNodeInfo(cx, assignment.Left, assignmentEntity, 1), target.Symbol, false, cx.CreateEntity(target.Symbol)); + new Expression(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 1).SetKind(ExprKind.ARRAY_ACCESS)) : + Access.Create(new ExpressionNodeInfo(Context, assignment.Left, assignmentEntity, 1), target.Symbol, false, Context.CreateEntity(target.Symbol)); if (assignment.Left is ImplicitElementAccessSyntax iea) { @@ -109,14 +109,14 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var indexChild = 0; foreach (var arg in iea.ArgumentList.Arguments) { - Expression.Create(cx, arg.Expression, access, indexChild++); + Expression.Create(Context, arg.Expression, access, indexChild++); } } } else { - cx.ModelError(init, "Unexpected object initialization"); - Create(cx, init, this, child++); + Context.ModelError(init, "Unexpected object initialization"); + Create(Context, init, this, child++); } } } @@ -133,16 +133,16 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var child = 0; foreach (var i in Syntax.Expressions) { - var collectionInfo = cx.GetModel(Syntax).GetCollectionInitializerSymbolInfo(i); - var addMethod = Method.Create(cx, collectionInfo.Symbol as IMethodSymbol); - var voidType = AnnotatedTypeSymbol.CreateNotAnnotated(cx.Compilation.GetSpecialType(SpecialType.System_Void)); + var collectionInfo = Context.GetModel(Syntax).GetCollectionInitializerSymbolInfo(i); + var addMethod = Method.Create(Context, collectionInfo.Symbol as IMethodSymbol); + var voidType = AnnotatedTypeSymbol.CreateNotAnnotated(Context.Compilation.GetSpecialType(SpecialType.System_Void)); - var invocation = new Expression(new ExpressionInfo(cx, voidType, cx.CreateLocation(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); + var invocation = new Expression(new ExpressionInfo(Context, voidType, Context.CreateLocation(i.GetLocation()), ExprKind.METHOD_INVOCATION, this, child++, false, null)); if (addMethod != null) trapFile.expr_call(invocation, addMethod); else - cx.ModelError(Syntax, "Unable to find an Add() method for collection initializer"); + Context.ModelError(Syntax, "Unable to find an Add() method for collection initializer"); if (i.Kind() == SyntaxKind.ComplexElementInitializerExpression) { @@ -154,12 +154,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var addChild = 0; foreach (var arg in init.Expressions) { - Create(cx, arg, invocation, addChild++); + Create(Context, arg, invocation, addChild++); } } else { - Create(cx, i, invocation, 0); + Create(Context, i, invocation, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs index 836aae35beb..ee69580f83a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs @@ -22,12 +22,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { case SyntaxKind.Interpolation: var interpolation = (InterpolationSyntax)c; - Create(cx, interpolation.Expression, this, child++); + Create(Context, interpolation.Expression, this, child++); break; case SyntaxKind.InterpolatedStringText: // Create a string literal var interpolatedText = (InterpolatedStringTextSyntax)c; - new Expression(new ExpressionInfo(cx, Type, cx.CreateLocation(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text)); + new Expression(new ExpressionInfo(Context, Type, Context.CreateLocation(c.GetLocation()), ExprKind.STRING_LITERAL, this, child++, false, interpolatedText.TextToken.Text)); break; default: throw new InternalError(c, $"Unhandled interpolation kind {c.Kind()}"); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs index 638822f3d27..2585ffe327f 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs @@ -37,15 +37,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions memberName = memberAccess.Name.Identifier.Text; if (Syntax.Expression.Kind() == SyntaxKind.SimpleMemberAccessExpression) // Qualified method call; `x.M()` - Create(cx, memberAccess.Expression, this, child++); + Create(Context, memberAccess.Expression, this, child++); else // Pointer member access; `x->M()` - Create(cx, Syntax.Expression, this, child++); + Create(Context, Syntax.Expression, this, child++); break; case MemberBindingExpressionSyntax memberBinding: // Conditionally qualified method call; `x?.M()` memberName = memberBinding.Name.Identifier.Text; - Create(cx, FindConditionalQualifier(memberBinding), this, child++); + Create(Context, FindConditionalQualifier(memberBinding), this, child++); MakeConditional(trapFile); break; case SimpleNameSyntax simpleName when (Kind == ExprKind.METHOD_INVOCATION): @@ -55,10 +55,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { // Implicit `this` qualifier; add explicitly - if (cx.GetModel(Syntax).GetEnclosingSymbol(Location.symbol.SourceSpan.Start) is IMethodSymbol callingMethod) - This.CreateImplicit(cx, callingMethod.ContainingType, Location, this, child++); + if (Context.GetModel(Syntax).GetEnclosingSymbol(Location.symbol.SourceSpan.Start) is IMethodSymbol callingMethod) + This.CreateImplicit(Context, callingMethod.ContainingType, Location, this, child++); else - cx.ModelError(Syntax, "Couldn't determine implicit this type"); + Context.ModelError(Syntax, "Couldn't determine implicit this type"); } else { @@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions break; default: // Delegate or function pointer call; `d()` - Create(cx, Syntax.Expression, this, child++); + Create(Context, Syntax.Expression, this, child++); break; } @@ -78,7 +78,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (memberName != null) trapFile.dynamic_member_name(this, memberName); else - cx.ModelError(Syntax, "Unable to get name for dynamic call."); + Context.ModelError(Syntax, "Unable to get name for dynamic call."); } PopulateArguments(trapFile, Syntax.ArgumentList, child); @@ -86,11 +86,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (target == null) { if (!isDynamicCall && !IsDelegateLikeCall(info)) - cx.ModelError(Syntax, "Unable to resolve target for call. (Compilation error?)"); + Context.ModelError(Syntax, "Unable to resolve target for call. (Compilation error?)"); return; } - var targetKey = Method.Create(cx, target); + var targetKey = Method.Create(Context, target); trapFile.expr_call(this, targetKey); } @@ -125,7 +125,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions .Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count) .Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count); - return cx.Extractor.Standalone ? + return Context.Extractor.Standalone ? candidates.FirstOrDefault() : candidates.SingleOrDefault(); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs index 741d108ba01..1c335474a68 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/IsPattern.cs @@ -12,8 +12,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); - Expressions.Pattern.Create(cx, Syntax.Pattern, this, 1); + Create(Context, Syntax.Expression, this, 0); + Expressions.Pattern.Create(Context, Syntax.Pattern, this, 1); } public static Expression Create(ExpressionNodeInfo info) => new IsPattern(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs index 40f200ef5ef..2cd23101b1c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Lambda.cs @@ -17,34 +17,34 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private void VisitParameter(ParameterSyntax p) { - var symbol = cx.GetModel(p).GetDeclaredSymbol(p); - Parameter.Create(cx, symbol, this); + var symbol = Context.GetModel(p).GetDeclaredSymbol(p); + Parameter.Create(Context, symbol, this); } private Lambda(ExpressionNodeInfo info, CSharpSyntaxNode body, IEnumerable @params) : base(info) { - if (cx.GetModel(info.Node).GetSymbolInfo(info.Node).Symbol is IMethodSymbol symbol) + if (Context.GetModel(info.Node).GetSymbolInfo(info.Node).Symbol is IMethodSymbol symbol) { - Modifier.ExtractModifiers(cx, info.Context.TrapWriter.Writer, this, symbol); + Modifier.ExtractModifiers(Context, info.Context.TrapWriter.Writer, this, symbol); } else { - cx.ModelError(info.Node, "Unknown declared symbol"); + Context.ModelError(info.Node, "Unknown declared symbol"); } // No need to use `Populate` as the population happens later - cx.PopulateLater(() => + Context.PopulateLater(() => { foreach (var param in @params) VisitParameter(param); if (body is ExpressionSyntax exprBody) - Create(cx, exprBody, this, 0); + Create(Context, exprBody, this, 0); else if (body is BlockSyntax blockBody) - Statements.Block.Create(cx, blockBody, this, 0); + Statements.Block.Create(Context, blockBody, this, 0); else - cx.ModelError(body, "Unhandled lambda body"); + Context.ModelError(body, "Unhandled lambda body"); }); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs index 751d6b6e92c..66f2fd8676a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MakeRef.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs index 7d2777540f0..fa9d3c9a6dd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/MemberAccess.cs @@ -9,16 +9,16 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol target) : base(info) { var trapFile = info.Context.TrapWriter.Writer; - Qualifier = Create(cx, qualifier, this, -1); + Qualifier = Create(Context, qualifier, this, -1); if (target == null) { if (info.Kind != ExprKind.DYNAMIC_MEMBER_ACCESS) - cx.ModelError(info.Node, "Could not determine target for member access"); + Context.ModelError(info.Node, "Could not determine target for member access"); } else { - var t = cx.CreateEntity(target); + var t = Context.CreateEntity(target); trapFile.expr_access(this, t); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs index 5a94a4333e8..df291c4e9fd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/AnonymousObjectCreation.cs @@ -17,32 +17,32 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - var target = cx.GetSymbolInfo(Syntax); + var target = Context.GetSymbolInfo(Syntax); var method = (IMethodSymbol)target.Symbol; if (method != null) { - trapFile.expr_call(this, Method.Create(cx, method)); + trapFile.expr_call(this, Method.Create(Context, method)); } var child = 0; var objectInitializer = Syntax.Initializers.Any() ? - new Expression(new ExpressionInfo(cx, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) : + new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) : null; foreach (var init in Syntax.Initializers) { // Create an "assignment" - var property = cx.GetModel(init).GetDeclaredSymbol(init); - var propEntity = Property.Create(cx, property); + var property = Context.GetModel(init).GetDeclaredSymbol(init); + var propEntity = Property.Create(Context, property); var type = property.GetAnnotatedType(); - var loc = cx.CreateLocation(init.GetLocation()); + var loc = Context.CreateLocation(init.GetLocation()); - var assignment = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null)); - Create(cx, init.Expression, assignment, 0); - Property.Create(cx, property); + var assignment = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.SIMPLE_ASSIGN, objectInitializer, child++, false, null)); + Create(Context, init.Expression, assignment, 0); + Property.Create(Context, property); - var access = new Expression(new ExpressionInfo(cx, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, false, null)); + var access = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.PROPERTY_ACCESS, assignment, 1, false, null)); trapFile.expr_access(access, propEntity); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs index 10f4df8bf7f..6f2c38b63db 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/BaseObjectCreation.cs @@ -22,22 +22,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions PopulateArguments(trapFile, Syntax.ArgumentList, 0); } - var target = cx.GetModel(Syntax).GetSymbolInfo(Syntax); + var target = Context.GetModel(Syntax).GetSymbolInfo(Syntax); if (target.Symbol is IMethodSymbol method) { - trapFile.expr_call(this, Method.Create(cx, method)); + trapFile.expr_call(this, Method.Create(Context, method)); } - if (IsDynamicObjectCreation(cx, Syntax)) + if (IsDynamicObjectCreation(Context, Syntax)) { - if (cx.GetModel(Syntax).GetTypeInfo(Syntax).Type is INamedTypeSymbol type && + if (Context.GetModel(Syntax).GetTypeInfo(Syntax).Type is INamedTypeSymbol type && !string.IsNullOrEmpty(type.Name)) { trapFile.dynamic_member_name(this, type.Name); } else { - cx.ModelError(Syntax, "Unable to get name for dynamic object creation."); + Context.ModelError(Syntax, "Unable to get name for dynamic object creation."); } } @@ -46,13 +46,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions switch (Syntax.Initializer.Kind()) { case SyntaxKind.CollectionInitializerExpression: - CollectionInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1).SetType(Type)); + CollectionInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type)); break; case SyntaxKind.ObjectInitializerExpression: - ObjectInitializer.Create(new ExpressionNodeInfo(cx, Syntax.Initializer, this, -1).SetType(Type)); + ObjectInitializer.Create(new ExpressionNodeInfo(Context, Syntax.Initializer, this, -1).SetType(Type)); break; default: - cx.ModelError("Unhandled initializer in object creation"); + Context.ModelError("Unhandled initializer in object creation"); break; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs index 51b2db20a9e..f51ab0cb810 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ObjectCreation/ExplicitObjectCreation.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions { base.PopulateExpression(trapFile); - TypeMention.Create(cx, Syntax.Type, this, Type); + TypeMention.Create(Context, Syntax.Type, this, Type); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs index 01df338d1b3..a8ea0a30780 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PointerMemberAccess.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); // !! We do not currently look at the member (or store the member name). } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs index 30c6058d95f..24d07441964 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/PostfixUnary.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, operand, this, 0); + Create(Context, operand, this, 0); OperatorCall(trapFile, Syntax); if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) && diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs index db5cd138155..2011f4ae367 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RangeExpression.cs @@ -13,9 +13,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { if (!(Syntax.LeftOperand is null)) - Expression.Create(cx, Syntax.LeftOperand, this, 0); + Expression.Create(Context, Syntax.LeftOperand, this, 0); if (!(Syntax.RightOperand is null)) - Expression.Create(cx, Syntax.RightOperand, this, 1); + Expression.Create(Context, Syntax.RightOperand, this, 1); } public static Expression Create(ExpressionNodeInfo info) => new RangeExpression(info).TryPopulate(); diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs index 5b38b9b8ee6..ef28f5d7e25 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Ref.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs index 37f7e2a3f76..815a5928f51 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefType.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs index 2372cc4bb09..7d9187533ae 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/RefValue.cs @@ -12,8 +12,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); - Create(cx, Syntax.Type, this, 1); // A type-access + Create(Context, Syntax.Expression, this, 0); + Create(Context, Syntax.Type, this, 1); // A type-access } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs index a4b89928e00..d55fe1781ce 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Sizeof.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - TypeAccess.Create(cx, Syntax.Type, this, 0); + TypeAccess.Create(Context, Syntax.Type, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs index a6095ec63a2..3dbe496cd4c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Switch.cs @@ -17,10 +17,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - SwitchedExpr = Expression.Create(cx, Syntax.GoverningExpression, this, -1); + SwitchedExpr = Expression.Create(Context, Syntax.GoverningExpression, this, -1); for (var i = 0; i < Syntax.Arms.Count; i++) { - new SwitchCase(cx, Syntax.Arms[i], this, i); + new SwitchCase(Context, Syntax.Arms[i], this, i); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs index 5ef8feaebb6..36d0b34bf95 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Throw.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs index f2911bdcf75..726f8f540d7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Tuple.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var child = 0; foreach (var argument in Syntax.Arguments.Select(a => a.Expression)) { - Expression.Create(cx, argument, this, child++); + Expression.Create(Context, argument, this, child++); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs index e5c0fd3ac66..54b9730e3d7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeAccess.cs @@ -18,17 +18,17 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (Type?.Symbol.ContainingType is null) { // namespace qualifier - TypeMention.Create(cx, maes.Name, this, Type, Syntax.GetLocation()); + TypeMention.Create(Context, maes.Name, this, Type, Syntax.GetLocation()); } else { // type qualifier - TypeMention.Create(cx, maes.Name, this, Type); - Create(cx, maes.Expression, this, -1); + TypeMention.Create(Context, maes.Name, this, Type); + Create(Context, maes.Expression, this, -1); } return; default: - TypeMention.Create(cx, (TypeSyntax)Syntax, this, Type); + TypeMention.Create(Context, (TypeSyntax)Syntax, this, Type); return; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs index 686e4156528..6e5dc3e05f1 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/TypeOf.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - TypeAccess.Create(cx, Syntax.Type, this, TypeAccessIndex); + TypeAccess.Create(Context, Syntax.Type, this, TypeAccessIndex); } public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, Extraction.Entities.Location location) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs index f3c2c73b074..8cad73d6565 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unary.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Operand, this, 0); + Create(Context, Syntax.Operand, this, 0); OperatorCall(trapFile, Syntax); if ((operatorKind == ExprKind.PRE_INCR || operatorKind == ExprKind.PRE_DECR) && diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs index 5ffcf414132..016c3fcefc8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Unchecked.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - Create(cx, Syntax.Expression, this, 0); + Create(Context, Syntax.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs index ace89464b96..ece87fd1f42 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/ElifDirective.cs @@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.directive_elifs(this, trivia.BranchTaken, trivia.ConditionValue, start, index); - Expression.Create(cx, trivia.Condition, this, 0); + Expression.Create(Context, trivia.Condition, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs index e1b81e60d8a..29c6f741620 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/IfDirective.cs @@ -16,7 +16,7 @@ namespace Semmle.Extraction.CSharp.Entities { trapFile.directive_ifs(this, trivia.BranchTaken, trivia.ConditionValue); - Expression.Create(cx, trivia.Condition, this, 0); + Expression.Create(Context, trivia.Condition, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs index 54681d317e9..470f54f379a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/LineDirective.cs @@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities if (!string.IsNullOrWhiteSpace(trivia.File.ValueText)) { - var file = Extraction.Entities.File.Create(cx, trivia.File.ValueText); + var file = Extraction.Entities.File.Create(Context, trivia.File.ValueText); trapFile.directive_line_file(this, file); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs index dff901fa826..572b77e2c73 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PragmaChecksumDirective.cs @@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities protected override void PopulatePreprocessor(TextWriter trapFile) { - var file = Extraction.Entities.File.Create(cx, trivia.File.ValueText); + var file = Extraction.Entities.File.Create(Context, trivia.File.ValueText); trapFile.pragma_checksums(this, file, trivia.Guid.ToString(), trivia.Bytes.ToString()); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs index 4575dd8b8dc..13e702603ab 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/PreprocessorDirectives/PreprocessorDirective.cs @@ -23,11 +23,11 @@ namespace Semmle.Extraction.CSharp.Entities PopulatePreprocessor(trapFile); trapFile.preprocessor_directive_active(this, trivia.IsActive); - trapFile.preprocessor_directive_location(this, cx.CreateLocation(ReportingLocation)); + trapFile.preprocessor_directive_location(this, Context.CreateLocation(ReportingLocation)); - if (!cx.Extractor.Standalone) + if (!Context.Extractor.Standalone) { - var compilation = Compilation.Create(cx); + var compilation = Compilation.Create(Context); trapFile.preprocessor_directive_compilation(this, compilation); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs index 6795c4a12df..b91b7582b51 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Property.cs @@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities protected Property(Context cx, IPropertySymbol init) : base(cx, init) { - type = new Lazy(() => Type.Create(Context, symbol.Type)); + type = new Lazy(() => Type.Create(base.Context, symbol.Type)); } private readonly Lazy type; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs index c3e2e15baf3..c50cad9b6cd 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Block.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { var child = 0; - foreach (var childStmt in Stmt.Statements.Select(c => Statement.Create(cx, c, this, child))) + foreach (var childStmt in Stmt.Statements.Select(c => Statement.Create(Context, c, this, child))) { child += childStmt.NumberOfStatements; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs index 8046bdb6e26..73a2582060b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Case.cs @@ -36,8 +36,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { var value = Stmt.Value; - Expression.Create(cx, value, this, 0); - Switch.LabelForValue(cx.GetModel(Stmt).GetConstantValue(value).Value); + Expression.Create(Context, value, this, 0); + Switch.LabelForValue(Context.GetModel(Stmt).GetConstantValue(value).Value); } public static CaseLabel Create(Context cx, CaseSwitchLabelSyntax node, Switch parent, int child) @@ -70,11 +70,11 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expressions.Pattern.Create(cx, Stmt.Pattern, this, 0); + Expressions.Pattern.Create(Context, Stmt.Pattern, this, 0); if (Stmt.WhenClause != null) { - Expression.Create(cx, Stmt.WhenClause.Condition, this, 1); + Expression.Create(Context, Stmt.WhenClause.Condition, this, 1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs index b9bddab82e2..f7484c72d56 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Catch.cs @@ -19,26 +19,26 @@ namespace Semmle.Extraction.CSharp.Entities.Statements if (hasVariableDeclaration) // A catch clause of the form 'catch(Ex ex) { ... }' { - var decl = Expressions.VariableDeclaration.Create(cx, Stmt.Declaration, false, this, 0); - trapFile.catch_type(this, Type.Create(cx, decl.Type).TypeRef, true); + var decl = Expressions.VariableDeclaration.Create(Context, Stmt.Declaration, false, this, 0); + trapFile.catch_type(this, Type.Create(Context, decl.Type).TypeRef, true); } else if (isSpecificCatchClause) // A catch clause of the form 'catch(Ex) { ... }' { - trapFile.catch_type(this, Type.Create(cx, cx.GetType(Stmt.Declaration.Type)).TypeRef, true); + trapFile.catch_type(this, Type.Create(Context, Context.GetType(Stmt.Declaration.Type)).TypeRef, true); } else // A catch clause of the form 'catch { ... }' { - var exception = Type.Create(cx, cx.Compilation.GetTypeByMetadataName(systemExceptionName)); + var exception = Type.Create(Context, Context.Compilation.GetTypeByMetadataName(systemExceptionName)); trapFile.catch_type(this, exception, false); } if (Stmt.Filter != null) { // For backward compatibility, the catch filter clause is child number 2. - Expression.Create(cx, Stmt.Filter.FilterExpression, this, 2); + Expression.Create(Context, Stmt.Filter.FilterExpression, this, 2); } - Create(cx, Stmt.Block, this, 1); + Create(Context, Stmt.Block, this, 1); } public static Catch Create(Context cx, CatchClauseSyntax node, Try parent, int child) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs index 4ce000bed3f..0f5766fad23 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Checked.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Statement.Create(cx, Stmt.Block, this, 0); + Statement.Create(Context, Stmt.Block, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs index 7cdcfb1f57b..e3518505270 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Do.cs @@ -19,8 +19,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Create(cx, Stmt.Statement, this, 1); - Expression.Create(cx, Stmt.Condition, this, 0); + Create(Context, Stmt.Statement, this, 1); + Expression.Create(Context, Stmt.Condition, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs index 252e867efa9..76d369bde23 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ExpressionStatement.cs @@ -18,9 +18,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); else - cx.ModelError(Stmt, "Invalid expression statement"); + Context.ModelError(Stmt, "Invalid expression statement"); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs index 7cd8350c7d1..1d01b1708f2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Fixed.cs @@ -19,8 +19,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - VariableDeclarations.Populate(cx, Stmt.Declaration, this, -1, childIncrement: -1); - Create(cx, Stmt.Statement, this, 0); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, -1, childIncrement: -1); + Create(Context, Stmt.Statement, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs index 15c7151a8a6..678373168f6 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/For.cs @@ -22,25 +22,25 @@ namespace Semmle.Extraction.CSharp.Entities.Statements var child = -1; if (Stmt.Declaration != null) - VariableDeclarations.Populate(cx, Stmt.Declaration, this, child, childIncrement: -1); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, child, childIncrement: -1); foreach (var init in Stmt.Initializers) { - Expression.Create(cx, init, this, child--); + Expression.Create(Context, init, this, child--); } if (Stmt.Condition != null) { - Expression.Create(cx, Stmt.Condition, this, 0); + Expression.Create(Context, Stmt.Condition, this, 0); } child = 1; foreach (var inc in Stmt.Incrementors) { - Expression.Create(cx, inc, this, child++); + Expression.Create(Context, inc, this, child++); } - Statement.Create(cx, Stmt.Statement, this, 1 + Stmt.Incrementors.Count); + Statement.Create(Context, Stmt.Statement, this, 1 + Stmt.Incrementors.Count); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs index e7bb987574e..bd9b1528a13 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/ForEach.cs @@ -29,23 +29,23 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Expression, this, 1); + Expression.Create(Context, Stmt.Expression, this, 1); - var semanticModel = cx.GetModel(Stmt); + var semanticModel = Context.GetModel(Stmt); var typeSymbol = semanticModel.GetDeclaredSymbol(Stmt); var type = typeSymbol.GetAnnotatedType(); - var location = cx.CreateLocation(Stmt.Identifier.GetLocation()); + var location = Context.CreateLocation(Stmt.Identifier.GetLocation()); - Expressions.VariableDeclaration.Create(cx, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0); + Expressions.VariableDeclaration.Create(Context, typeSymbol, type, Stmt.Type, location, Stmt.Type.IsVar, this, 0); - Statement.Create(cx, Stmt.Statement, this, 2); + Statement.Create(Context, Stmt.Statement, this, 2); var info = semanticModel.GetForEachStatementInfo(Stmt); if (info.Equals(default)) { - cx.ExtractionError("Could not get foreach statement info", null, cx.CreateLocation(this.ReportingLocation), severity: Util.Logging.Severity.Info); + Context.ExtractionError("Could not get foreach statement info", null, Context.CreateLocation(this.ReportingLocation), severity: Util.Logging.Severity.Info); return; } @@ -53,31 +53,31 @@ namespace Semmle.Extraction.CSharp.Entities.Statements if (info.GetEnumeratorMethod != null) { - var m = Method.Create(cx, info.GetEnumeratorMethod); + var m = Method.Create(Context, info.GetEnumeratorMethod); trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.GetEnumeratorMethod); } if (info.MoveNextMethod != null) { - var m = Method.Create(cx, info.MoveNextMethod); + var m = Method.Create(Context, info.MoveNextMethod); trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.MoveNextMethod); } if (info.DisposeMethod != null) { - var m = Method.Create(cx, info.DisposeMethod); + var m = Method.Create(Context, info.DisposeMethod); trapFile.foreach_stmt_desugar(this, m, ForeachSymbolType.DisposeMethod); } if (info.CurrentProperty != null) { - var p = Property.Create(cx, info.CurrentProperty); + var p = Property.Create(Context, info.CurrentProperty); trapFile.foreach_stmt_desugar(this, p, ForeachSymbolType.CurrentProperty); } if (info.ElementType != null) { - var t = Type.Create(cx, info.ElementType); + var t = Type.Create(Context, info.ElementType); trapFile.foreach_stmt_desugar(this, t, ForeachSymbolType.ElementType); } } @@ -97,9 +97,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Variable, this, 0); - Expression.Create(cx, Stmt.Expression, this, 1); - Statement.Create(cx, Stmt.Statement, this, 2); + Expression.Create(Context, Stmt.Variable, this, 0); + Expression.Create(Context, Stmt.Expression, this, 1); + Statement.Create(Context, Stmt.Statement, this, 2); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs index 772d69cff7c..20548dd056a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Goto.cs @@ -40,8 +40,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements trapFile.exprorstmt_name(this, target); break; case StmtKind.GOTO_CASE: - Expr = Expression.Create(cx, Stmt.Expression, this, 0); - ConstantValue = Switch.LabelForValue(cx.GetModel(Stmt).GetConstantValue(Stmt.Expression).Value); + Expr = Expression.Create(Context, Stmt.Expression, this, 0); + ConstantValue = Switch.LabelForValue(Context.GetModel(Stmt).GetConstantValue(Stmt.Expression).Value); break; case StmtKind.GOTO_DEFAULT: ConstantValue = Switch.DefaultLabel; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs index b132c6ebe54..010cd9a793b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/If.cs @@ -18,12 +18,12 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Condition, this, 0); + Expression.Create(Context, Stmt.Condition, this, 0); - Create(cx, Stmt.Statement, this, 1); + Create(Context, Stmt.Statement, this, 1); if (Stmt.Else != null) - Create(cx, Stmt.Else.Statement, this, 2); + Create(Context, Stmt.Else.Statement, this, 2); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs index fe69af917ba..d549008daaf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Labeled.cs @@ -30,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements // For compatibility with the Mono extractor, make insert the labelled statement into the same block // as this one. The parent MUST be a block statement. - labelledStmt = Statement.Create(cx, Stmt.Statement, parent, child + 1); + labelledStmt = Statement.Create(Context, Stmt.Statement, parent, child + 1); } public override int NumberOfStatements => 1 + labelledStmt.NumberOfStatements; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs index 87559681fd8..b147e5693ca 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalDeclaration.cs @@ -30,8 +30,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - VariableDeclarations.Populate(cx, Stmt.Declaration, this, 0); - cx.BindComments(this, Stmt.GetLocation()); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, 0); + Context.BindComments(this, Stmt.GetLocation()); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs index 5e417fd8885..aaebd538c67 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/LocalFunction.cs @@ -26,7 +26,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { get { - var m = cx.GetModel(Stmt); + var m = Context.GetModel(Stmt); return m.GetDeclaredSymbol(Stmt) as IMethodSymbol; } } @@ -34,7 +34,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements /// /// Gets the function defined by this local statement. /// - private Entities.LocalFunction Function => Entities.LocalFunction.Create(cx, Symbol); + private Entities.LocalFunction Function => Entities.LocalFunction.Create(Context, Symbol); protected override void PopulateStatement(TextWriter trapFile) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs index fbcb346b367..141edcea63a 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Lock.cs @@ -18,8 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Expression, this, 0); - Statement.Create(cx, Stmt.Statement, this, 1); + Expression.Create(Context, Stmt.Expression, this, 0); + Statement.Create(Context, Stmt.Statement, this, 1); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs index 2ff04b82b87..64692630b4c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Return.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs index f64067be9c4..df73554f389 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Switch.cs @@ -30,17 +30,17 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); var childIndex = 0; foreach (var section in Stmt.Sections) { - foreach (var stmt in section.Labels.Select(label => Case.Create(cx, label, this, childIndex))) + foreach (var stmt in section.Labels.Select(label => Case.Create(Context, label, this, childIndex))) { childIndex += stmt.NumberOfStatements; } - foreach (var stmt in section.Statements.Select(s => Create(cx, s, this, childIndex))) + foreach (var stmt in section.Statements.Select(s => Create(Context, s, this, childIndex))) { childIndex += stmt.NumberOfStatements; } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs index c550b1f1e39..dbff60d890b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Throw.cs @@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs index 5a6937790c2..bb17c2beaa2 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Try.cs @@ -22,14 +22,14 @@ namespace Semmle.Extraction.CSharp.Entities.Statements var child = 1; foreach (var c in Stmt.Catches) { - Catch.Create(cx, c, this, child++); + Catch.Create(Context, c, this, child++); } - Create(cx, Stmt.Block, this, 0); + Create(Context, Stmt.Block, this, 0); if (Stmt.Finally != null) { - Create(cx, Stmt.Finally.Block, this, -1); + Create(Context, Stmt.Finally.Block, this, -1); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs index 2d69bdc8d4c..37de04f870b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unchecked.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Statement.Create(cx, Stmt.Block, this, 0); + Statement.Create(Context, Stmt.Block, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs index 4e371604333..936c5e84296 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Unsafe.cs @@ -18,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Create(cx, Stmt.Block, this, 0); + Create(Context, Stmt.Block, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs index 93d0f6a88ff..b62e6556a8c 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Using.cs @@ -20,13 +20,13 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { if (Stmt.Declaration != null) - VariableDeclarations.Populate(cx, Stmt.Declaration, this, -1, childIncrement: -1); + VariableDeclarations.Populate(Context, Stmt.Declaration, this, -1, childIncrement: -1); if (Stmt.Expression != null) - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); if (Stmt.Statement != null) - Statement.Create(cx, Stmt.Statement, this, 1); + Statement.Create(Context, Stmt.Statement, this, 1); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs index 8def91a8418..99e96e7b683 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/While.cs @@ -18,8 +18,8 @@ namespace Semmle.Extraction.CSharp.Entities.Statements protected override void PopulateStatement(TextWriter trapFile) { - Expression.Create(cx, Stmt.Condition, this, 0); - Create(cx, Stmt.Statement, this, 1); + Expression.Create(Context, Stmt.Condition, this, 0); + Create(Context, Stmt.Statement, this, 1); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs index 9aace8e0b83..605a7cacdbc 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Statements/Yield.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements { if (Stmt.Expression != null) { - Expression.Create(cx, Stmt.Expression, this, 0); + Expression.Create(Context, Stmt.Expression, this, 0); } } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs index e05c2d0c102..57f309cad8b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/TypeMention.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities case NullableTypeSyntax nts: // int[]? -> int[] -> int // int? -> int? - return cx.GetTypeInfo(nts.ElementType).Type.IsReferenceType + return Context.GetTypeInfo(nts.ElementType).Type.IsReferenceType ? GetArrayElementType(nts.ElementType) : nts; case PointerTypeSyntax pts: @@ -65,7 +65,7 @@ namespace Semmle.Extraction.CSharp.Entities case SyntaxKind.ArrayType: case SyntaxKind.PointerType: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - Create(cx, GetArrayElementType(syntax), this, GetArrayElementType(type)); + Create(Context, GetArrayElementType(syntax), this, GetArrayElementType(type)); return; case SyntaxKind.NullableType: var nts = (NullableTypeSyntax)syntax; @@ -74,39 +74,39 @@ namespace Semmle.Extraction.CSharp.Entities if (!nt.symbol.IsReferenceType) { Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - Create(cx, nts.ElementType, this, nt.TypeArguments[0]); + Create(Context, nts.ElementType, this, nt.TypeArguments[0]); } else { - Create(cx, nts.ElementType, parent, type); + Create(Context, nts.ElementType, parent, type); } } else if (type is ArrayType) { - Create(cx, nts.ElementType, parent, type); + Create(Context, nts.ElementType, parent, type); } return; case SyntaxKind.TupleType: var tts = (TupleTypeSyntax)syntax; var tt = (TupleType)type; Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - tts.Elements.Zip(tt.TupleElements, (s, t) => Create(cx, s.Type, this, t.Type)).Enumerate(); + tts.Elements.Zip(tt.TupleElements, (s, t) => Create(Context, s.Type, this, t.Type)).Enumerate(); return; case SyntaxKind.GenericName: Emit(trapFile, loc ?? syntax.GetLocation(), parent, type); - cx.PopulateLater(() => + Context.PopulateLater(() => ((GenericNameSyntax)syntax) .TypeArgumentList .Arguments - .Zip(type.TypeMentions, (s, t) => Create(cx, s, this, t)).Enumerate()); + .Zip(type.TypeMentions, (s, t) => Create(Context, s, this, t)).Enumerate()); return; case SyntaxKind.QualifiedName: var qns = (QualifiedNameSyntax)syntax; - var right = Create(cx, qns.Right, parent, type); + var right = Create(Context, qns.Right, parent, type); if (type.ContainingType is object) { // Type qualifier - Create(cx, qns.Left, right, type.ContainingType); + Create(Context, qns.Left, right, type.ContainingType); } return; default: @@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp.Entities private void Emit(TextWriter trapFile, Microsoft.CodeAnalysis.Location loc, IEntity parent, Type type) { trapFile.type_mention(this, type.TypeRef, parent); - trapFile.type_mention_location(this, cx.CreateLocation(loc)); + trapFile.type_mention_location(this, Context.CreateLocation(loc)); } public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs index 8c96a334565..34fc6f5ccba 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/Type.cs @@ -326,6 +326,7 @@ namespace Semmle.Extraction.CSharp.Entities protected Type(Context cx, T init) : base(cx, init) { } + // todo: change this with .net 5 to be an override public new T symbol => (T)base.symbol; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs index d08a1320ba2..96ce5f339cf 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UsingDirective.cs @@ -21,30 +21,30 @@ namespace Semmle.Extraction.CSharp.Entities protected override void Populate(TextWriter trapFile) { - var info = cx.GetModel(node).GetSymbolInfo(node.Name); + var info = Context.GetModel(node).GetSymbolInfo(node.Name); if (node.StaticKeyword.Kind() == SyntaxKind.None) { // A normal using if (info.Symbol is INamespaceSymbol namespaceSymbol) { - var ns = Namespace.Create(cx, namespaceSymbol); + var ns = Namespace.Create(Context, namespaceSymbol); trapFile.using_namespace_directives(this, ns); - trapFile.using_directive_location(this, cx.CreateLocation(ReportingLocation)); + trapFile.using_directive_location(this, Context.CreateLocation(ReportingLocation)); } else { - cx.Extractor.MissingNamespace(node.Name.ToFullString(), cx.FromSource); - cx.ModelError(node, "Namespace not found"); + Context.Extractor.MissingNamespace(node.Name.ToFullString(), Context.FromSource); + Context.ModelError(node, "Namespace not found"); return; } } else { // A "using static" - var m = Type.Create(cx, (ITypeSymbol)info.Symbol); + var m = Type.Create(Context, (ITypeSymbol)info.Symbol); trapFile.using_static_directives(this, m.TypeRef); - trapFile.using_directive_location(this, cx.CreateLocation(ReportingLocation)); + trapFile.using_directive_location(this, Context.CreateLocation(ReportingLocation)); } if (parent != null) diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 7f5ef6b1110..a4b84d5d047 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -73,7 +73,7 @@ namespace Semmle.Extraction } #if DEBUG_LABELS - private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity) + private void CheckEntityHasUniqueLabel(string id, CachedEntity entity) { if (idLabelCache.ContainsKey(id)) { @@ -89,12 +89,12 @@ namespace Semmle.Extraction public Label GetNewLabel() => new Label(GetNewId()); public TEntity CreateEntity(ICachedEntityFactory factory, object cacheKey, TInit init) - where TEntity : ICachedEntity => + where TEntity : CachedEntity => cacheKey is ISymbol s ? CreateEntity(factory, s, init, symbolEntityCache) : CreateEntity(factory, cacheKey, init, objectEntityCache); public TEntity CreateEntityFromSymbol(ICachedEntityFactory factory, TSymbol init) where TSymbol : ISymbol - where TEntity : ICachedEntity => CreateEntity(factory, init, init, symbolEntityCache); + where TEntity : CachedEntity => CreateEntity(factory, init, init, symbolEntityCache); /// /// Creates and populates a new entity, or returns the existing one from the cache. @@ -104,9 +104,9 @@ namespace Semmle.Extraction /// The initializer for the entity. /// The dictionary to use for caching. /// The new/existing entity. - private TEntity CreateEntity(ICachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) + private TEntity CreateEntity(ICachedEntityFactory factory, TCacheKey cacheKey, TInit init, IDictionary dictionary) where TCacheKey : notnull - where TEntity : ICachedEntity + where TEntity : CachedEntity { if (dictionary.TryGetValue(cacheKey, out var cached)) return (TEntity)cached; @@ -143,7 +143,7 @@ namespace Semmle.Extraction /// /// The entity to extract. /// True only on the first call for a particular entity. - public bool ExtractGenerics(ICachedEntity entity) + public bool ExtractGenerics(CachedEntity entity) { if (extractedGenerics.Contains(entity.Label)) { @@ -158,18 +158,18 @@ namespace Semmle.Extraction /// Creates a fresh label with ID "*", and set it on the /// supplied object. /// - public void AddFreshLabel(IEntity entity) + public void AddFreshLabel(Entity entity) { entity.Label = GetNewLabel(); entity.DefineFreshLabel(TrapWriter.Writer); } #if DEBUG_LABELS - private readonly Dictionary idLabelCache = new Dictionary(); + private readonly Dictionary idLabelCache = new Dictionary(); #endif - private readonly IDictionary objectEntityCache = new Dictionary(); - private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); + private readonly IDictionary objectEntityCache = new Dictionary(); + private readonly IDictionary symbolEntityCache = new Dictionary(10000, SymbolEqualityComparer.Default); private readonly HashSet public void ExtractRecursive() { - foreach (var l in symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax().GetLocation())) + foreach (var l in Symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax().GetLocation())) { Context.BindComments(this, l); } - foreach (var member in symbol.GetMembers()) + foreach (var member in Symbol.GetMembers()) { switch (member.Kind) { @@ -211,21 +211,21 @@ namespace Semmle.Extraction.CSharp.Entities /// public void PopulateGenerics() { - if (symbol == null || !NeedsPopulation || !Context.ExtractGenerics(this)) + if (Symbol == null || !NeedsPopulation || !Context.ExtractGenerics(this)) return; var members = new List(); - foreach (var member in symbol.GetMembers()) + foreach (var member in Symbol.GetMembers()) members.Add(member); - foreach (var member in symbol.GetTypeMembers()) + foreach (var member in Symbol.GetTypeMembers()) members.Add(member); // Mono extractor puts all BASE interface members as members of the current interface. - if (symbol.TypeKind == TypeKind.Interface) + if (Symbol.TypeKind == TypeKind.Interface) { - foreach (var baseInterface in symbol.Interfaces) + foreach (var baseInterface in Symbol.Interfaces) { foreach (var member in baseInterface.GetMembers()) members.Add(member); @@ -239,10 +239,10 @@ namespace Semmle.Extraction.CSharp.Entities Context.CreateEntity(member); } - if (symbol.BaseType != null) - Create(Context, symbol.BaseType).PopulateGenerics(); + if (Symbol.BaseType != null) + Create(Context, Symbol.BaseType).PopulateGenerics(); - foreach (var i in symbol.Interfaces) + foreach (var i in Symbol.Interfaces) { Create(Context, i).PopulateGenerics(); } @@ -250,7 +250,7 @@ namespace Semmle.Extraction.CSharp.Entities public void ExtractRecursive(TextWriter trapFile, IEntity parent) { - if (symbol.ContainingSymbol.Kind == SymbolKind.Namespace && !symbol.ContainingNamespace.IsGlobalNamespace) + if (Symbol.ContainingSymbol.Kind == SymbolKind.Namespace && !Symbol.ContainingNamespace.IsGlobalNamespace) { trapFile.parent_namespace_declaration(this, (NamespaceDeclaration)parent); } @@ -315,10 +315,10 @@ namespace Semmle.Extraction.CSharp.Entities public override bool Equals(object obj) { var other = obj as Type; - return other?.GetType() == GetType() && SymbolEqualityComparer.Default.Equals(other.symbol, symbol); + return other?.GetType() == GetType() && SymbolEqualityComparer.Default.Equals(other.Symbol, Symbol); } - public override int GetHashCode() => SymbolEqualityComparer.Default.GetHashCode(symbol); + public override int GetHashCode() => SymbolEqualityComparer.Default.GetHashCode(Symbol); } internal abstract class Type : Type where T : ITypeSymbol @@ -327,6 +327,6 @@ namespace Semmle.Extraction.CSharp.Entities : base(cx, init) { } // todo: change this with .net 5 to be an override - public new T symbol => (T)base.symbol; + public new T Symbol => (T)base.Symbol; } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs index e92a3891704..fc8ac7e39d8 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/TypeParameter.cs @@ -24,22 +24,22 @@ namespace Semmle.Extraction.CSharp.Entities var constraints = new TypeParameterConstraints(Context); trapFile.type_parameter_constraints(constraints, this); - if (symbol.HasReferenceTypeConstraint) + if (Symbol.HasReferenceTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 1); - if (symbol.HasValueTypeConstraint) + if (Symbol.HasValueTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 2); - if (symbol.HasConstructorConstraint) + if (Symbol.HasConstructorConstraint) trapFile.general_type_parameter_constraints(constraints, 3); - if (symbol.HasUnmanagedTypeConstraint) + if (Symbol.HasUnmanagedTypeConstraint) trapFile.general_type_parameter_constraints(constraints, 4); - if (symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated) + if (Symbol.ReferenceTypeConstraintNullableAnnotation == NullableAnnotation.Annotated) trapFile.general_type_parameter_constraints(constraints, 5); - foreach (var abase in symbol.GetAnnotatedTypeConstraints()) + foreach (var abase in Symbol.GetAnnotatedTypeConstraints()) { var t = Create(Context, abase.Symbol); trapFile.specific_type_parameter_constraints(constraints, t.TypeRef); @@ -47,19 +47,19 @@ namespace Semmle.Extraction.CSharp.Entities trapFile.specific_type_parameter_nullability(constraints, t.TypeRef, NullabilityEntity.Create(Context, Nullability.Create(abase))); } - trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, symbol.Name); + trapFile.types(this, Kinds.TypeKind.TYPE_PARAMETER, Symbol.Name); - var parentNs = Namespace.Create(Context, symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : symbol.ContainingNamespace); + var parentNs = Namespace.Create(Context, Symbol.TypeParameterKind == TypeParameterKind.Method ? Context.Compilation.GlobalNamespace : Symbol.ContainingNamespace); trapFile.parent_namespace(this, parentNs); - foreach (var l in symbol.Locations) + foreach (var l in Symbol.Locations) { trapFile.type_location(this, Context.CreateLocation(l)); } if (IsSourceDeclaration) { - var declSyntaxReferences = symbol.DeclaringSyntaxReferences + var declSyntaxReferences = Symbol.DeclaringSyntaxReferences .Select(d => d.GetSyntax()) .Select(s => s.Parent) .Where(p => p != null) @@ -69,7 +69,7 @@ namespace Semmle.Extraction.CSharp.Entities clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); clauses = clauses.Concat(declSyntaxReferences.OfType().SelectMany(c => c.ConstraintClauses)); - foreach (var clause in clauses.Where(c => c.Name.Identifier.Text == symbol.Name)) + foreach (var clause in clauses.Where(c => c.Name.Identifier.Text == Symbol.Name)) { TypeMention.Create(Context, clause.Name, this, this); foreach (var constraint in clause.Constraints.OfType()) @@ -92,13 +92,13 @@ namespace Semmle.Extraction.CSharp.Entities { get { - switch (symbol.Variance) + switch (Symbol.Variance) { case VarianceKind.None: return Variance.None; case VarianceKind.Out: return Variance.Out; case VarianceKind.In: return Variance.In; default: - throw new InternalError($"Unexpected VarianceKind {symbol.Variance}"); + throw new InternalError($"Unexpected VarianceKind {Symbol.Variance}"); } } } @@ -107,22 +107,22 @@ namespace Semmle.Extraction.CSharp.Entities { string kind; IEntity containingEntity; - switch (symbol.TypeParameterKind) + switch (Symbol.TypeParameterKind) { case TypeParameterKind.Method: kind = "methodtypeparameter"; - containingEntity = Method.Create(Context, (IMethodSymbol)symbol.ContainingSymbol); + containingEntity = Method.Create(Context, (IMethodSymbol)Symbol.ContainingSymbol); break; case TypeParameterKind.Type: kind = "typeparameter"; - containingEntity = Create(Context, symbol.ContainingType); + containingEntity = Create(Context, Symbol.ContainingType); break; default: - throw new InternalError(symbol, $"Unhandled type parameter kind {symbol.TypeParameterKind}"); + throw new InternalError(Symbol, $"Unhandled type parameter kind {Symbol.TypeParameterKind}"); } trapFile.WriteSubId(containingEntity); trapFile.Write('_'); - trapFile.Write(symbol.Ordinal); + trapFile.Write(Symbol.Ordinal); trapFile.Write(';'); trapFile.Write(kind); } diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs index d4c6fa457c1..2643363773b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs @@ -15,10 +15,10 @@ namespace Semmle.Extraction.CSharp.Entities PopulateMethod(trapFile); PopulateModifiers(trapFile); - var returnType = Type.Create(Context, symbol.ReturnType); + var returnType = Type.Create(Context, Symbol.ReturnType); trapFile.operators(this, - symbol.Name, - OperatorSymbol(Context, symbol.Name), + Symbol.Name, + OperatorSymbol(Context, Symbol.Name), ContainingType, returnType.TypeRef, (UserOperator)OriginalDefinition); @@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities if (IsSourceDeclaration) { - var declSyntaxReferences = symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).ToArray(); + var declSyntaxReferences = Symbol.DeclaringSyntaxReferences.Select(s => s.GetSyntax()).ToArray(); foreach (var declaration in declSyntaxReferences.OfType()) TypeMention.Create(Context, declaration.ReturnType, this, returnType); foreach (var declaration in declSyntaxReferences.OfType()) @@ -38,7 +38,7 @@ namespace Semmle.Extraction.CSharp.Entities ContainingType.PopulateGenerics(); } - public override bool NeedsPopulation => Context.Defines(symbol) || IsImplicitOperator(out _); + public override bool NeedsPopulation => Context.Defines(Symbol) || IsImplicitOperator(out _); public override Type ContainingType { @@ -57,22 +57,22 @@ namespace Semmle.Extraction.CSharp.Entities /// private bool IsImplicitOperator(out ITypeSymbol containingType) { - containingType = symbol.ContainingType; + containingType = Symbol.ContainingType; if (containingType != null) { var containingNamedType = containingType as INamedTypeSymbol; return containingNamedType == null || - !containingNamedType.GetMembers(symbol.Name).Contains(symbol); + !containingNamedType.GetMembers(Symbol.Name).Contains(Symbol); } - var pointerType = symbol.Parameters.Select(p => p.Type).OfType().FirstOrDefault(); + var pointerType = Symbol.Parameters.Select(p => p.Type).OfType().FirstOrDefault(); if (pointerType != null) { containingType = pointerType; return true; } - Context.ModelError(symbol, "Unexpected implicit operator"); + Context.ModelError(Symbol, "Unexpected implicit operator"); return true; } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs index e8b1e2cb46b..42fe1f2b30b 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Assembly.cs @@ -38,12 +38,12 @@ namespace Semmle.Extraction.Entities public override bool NeedsPopulation => true; public override int GetHashCode() => - symbol == null ? 91187354 : symbol.GetHashCode(); + Symbol == null ? 91187354 : Symbol.GetHashCode(); public override bool Equals(object? obj) { if (obj is Assembly other && other.GetType() == typeof(Assembly)) - return Equals(symbol, other.symbol); + return Equals(Symbol, other.Symbol); return false; } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs b/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs index a5b5798d28b..6e676ab90e1 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Base/CachedEntity`1.cs @@ -30,9 +30,11 @@ namespace Semmle.Extraction /// The type of the symbol. public abstract class CachedEntity : CachedEntity { + public TSymbol Symbol { get; } + protected CachedEntity(Context context, TSymbol symbol) : base(context) { - this.symbol = symbol; + this.Symbol = symbol; } /// @@ -48,23 +50,14 @@ namespace Semmle.Extraction } } - public TSymbol symbol - { - get; - } - - //object? ICachedEntity.UnderlyingObject => symbol; - - public TSymbol UnderlyingObject => symbol; - public override bool NeedsPopulation { get; } - public override int GetHashCode() => symbol is null ? 0 : symbol.GetHashCode(); + public override int GetHashCode() => Symbol is null ? 0 : Symbol.GetHashCode(); public override bool Equals(object? obj) { var other = obj as CachedEntity; - return other?.GetType() == GetType() && Equals(other.symbol, symbol); + return other?.GetType() == GetType() && Equals(other.Symbol, Symbol); } public override TrapStackBehaviour TrapStackBehaviour { get; } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs index 917d15419e8..c84a6247d69 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Folder.cs @@ -8,8 +8,8 @@ namespace Semmle.Extraction.Entities public override void Populate(TextWriter trapFile) { - trapFile.folders(this, symbol.Value, symbol.NameWithoutExtension); - if (symbol.ParentDirectory is PathTransformer.ITransformedPath parent) + trapFile.folders(this, Symbol.Value, Symbol.NameWithoutExtension); + if (Symbol.ParentDirectory is PathTransformer.ITransformedPath parent) trapFile.containerparent(Create(Context, parent), this); } @@ -17,7 +17,7 @@ namespace Semmle.Extraction.Entities public override void WriteId(System.IO.TextWriter trapFile) { - trapFile.Write(symbol.DatabaseId); + trapFile.Write(Symbol.DatabaseId); trapFile.Write(";folder"); } @@ -35,11 +35,11 @@ namespace Semmle.Extraction.Entities public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel; - public override int GetHashCode() => symbol.GetHashCode(); + public override int GetHashCode() => Symbol.GetHashCode(); public override bool Equals(object? obj) { - return obj is Folder folder && Equals(folder.symbol, symbol); + return obj is Folder folder && Equals(folder.Symbol, Symbol); } } } diff --git a/csharp/extractor/Semmle.Extraction/Entities/Location.cs b/csharp/extractor/Semmle.Extraction/Entities/Location.cs index cdd3c9a50dc..b2bfff06374 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/Location.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/Location.cs @@ -8,7 +8,7 @@ namespace Semmle.Extraction.Entities protected Location(Context cx, Microsoft.CodeAnalysis.Location? init) : base(cx, init) { } - public override Microsoft.CodeAnalysis.Location? ReportingLocation => symbol; + public override Microsoft.CodeAnalysis.Location? ReportingLocation => Symbol; public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel; } diff --git a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs index 6b9d495db19..4e1726d6d07 100644 --- a/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction/Entities/SourceLocation.cs @@ -30,7 +30,7 @@ namespace Semmle.Extraction.Entities Position.Span.Start.Line + 1, Position.Span.Start.Character + 1, Position.Span.End.Line + 1, Position.Span.End.Character); - var mapped = symbol!.GetMappedLineSpan(); + var mapped = Symbol!.GetMappedLineSpan(); if (mapped.HasMappedPath && mapped.IsValid) { var mappedLoc = Create(Context, Microsoft.CodeAnalysis.Location.Create(mapped.Path, default, mapped.Span)); diff --git a/csharp/extractor/Semmle.Extraction/Message.cs b/csharp/extractor/Semmle.Extraction/Message.cs index a100a69a285..c68efa66ce0 100644 --- a/csharp/extractor/Semmle.Extraction/Message.cs +++ b/csharp/extractor/Semmle.Extraction/Message.cs @@ -44,8 +44,8 @@ namespace Semmle.Extraction sb.Append(Text); if (!string.IsNullOrEmpty(EntityText)) sb.Append(" in ").Append(EntityText); - if (!(Location is null) && !(Location.UnderlyingObject is null)) - sb.Append(" at ").Append(Location.UnderlyingObject.GetLineSpan()); + if (!(Location is null) && !(Location.Symbol is null)) + sb.Append(" at ").Append(Location.Symbol.GetLineSpan()); if (!string.IsNullOrEmpty(StackTrace)) sb.Append(" ").Append(StackTrace); return sb.ToString(); From a75b952333272eb8e133e12fe99edb6bd437c286 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 15 Feb 2021 09:58:31 +0100 Subject: [PATCH 388/429] Fix Type.GetQualifiedName() --- .../Semmle.Extraction.CIL/Entities/Method.cs | 3 ++- .../Semmle.Extraction.CIL/Entities/Namespace.cs | 3 ++- .../extractor/Semmle.Extraction.CIL/Entities/Type.cs | 7 ++----- .../Semmle.Extraction.CIL/Entities/TypeContainer.cs | 12 ++++++++++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index e2887963edf..d1302837c16 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -62,9 +62,10 @@ namespace Semmle.Extraction.CIL.Entities param.WriteId(trapFile, this); } trapFile.Write(')'); - trapFile.Write(";cil-method"); } + public override string IdSuffix => ";cil-method"; + protected IEnumerable PopulateFlags { get diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs index 5f909b7b336..5d498c5ac54 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs @@ -22,9 +22,10 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write('.'); } trapFile.Write(Name); - trapFile.Write(";namespace"); } + public override string IdSuffix => ";namespacee"; + public override bool Equals(object? obj) { if (obj is Namespace ns && Name == ns.Name) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index 9f78c5066e0..ad5a6ababaa 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -45,12 +45,9 @@ namespace Semmle.Extraction.CIL.Entities /// public abstract void WriteId(TextWriter trapFile, bool inContext); - public sealed override void WriteId(TextWriter trapFile) - { - WriteId(trapFile, false); - trapFile.Write(";cil-type"); - } + public sealed override void WriteId(TextWriter trapFile) => WriteId(trapFile, false); + public override string IdSuffix => ";cil-type"; /// /// Returns the friendly qualified name of types, such as diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs index d8058593277..106b6fe83be 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/TypeContainer.cs @@ -1,5 +1,3 @@ -using System; -using Microsoft.CodeAnalysis; using System.Collections.Generic; using System.IO; @@ -14,6 +12,16 @@ namespace Semmle.Extraction.CIL.Entities { } + public abstract string IdSuffix { get; } + + public override void WriteQuotedId(TextWriter trapFile) + { + trapFile.Write("@\""); + WriteId(trapFile); + trapFile.Write(IdSuffix); + trapFile.Write('\"'); + } + public abstract IEnumerable MethodParameters { get; } public abstract IEnumerable TypeParameters { get; } } From 04f15ad43a10ca303ce5eb7a353e72d108f8bb58 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Feb 2021 09:49:09 +0000 Subject: [PATCH 389/429] C++: BSL support in StdPairConstructor. --- cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll index 9076220cc22..755f6a48520 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdPair.qll @@ -44,7 +44,7 @@ class StdPairCopyishConstructor extends Constructor, TaintFunction { * Additional model for `std::pair` constructors. */ private class StdPairConstructor extends Constructor, TaintFunction { - StdPairConstructor() { this.hasQualifiedName("std", "pair", "pair") } + StdPairConstructor() { this.getDeclaringType() instanceof StdPair } /** * Gets the index of a parameter to this function that is a reference to From 3a1888166030838644aa9e1d0b1c4c47d9f7aca3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Mon, 15 Feb 2021 00:00:48 +0100 Subject: [PATCH 390/429] Python: Restructure query file location Since I can never remember the CWE numbers --- .../ExternalAPIs}/ExternalAPISinkExample.py | 0 .../ExternalAPIs}/ExternalAPITaintStepExample.py | 0 .../CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPIs.qll | 0 .../ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.qhelp | 0 .../ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.ql | 0 .../ExternalAPIs}/UntrustedDataToExternalAPI.qhelp | 0 .../ExternalAPIs}/UntrustedDataToExternalAPI.ql | 0 .../BindToAllInterfaces}/BindToAllInterfaces.py | 0 .../BindToAllInterfaces}/BindToAllInterfaces.qhelp | 0 .../BindToAllInterfaces}/BindToAllInterfaces.ql | 0 .../{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.py | 0 .../{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.qhelp | 0 .../{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.ql | 0 .../HTTPSRequestWithoutCertValidation.qhelp} | 0 .../HTTPSRequestWithoutCertValidation.ql} | 0 .../HTTPSRequestWithoutCertValidation}/examples/make_request.py | 0 .../HardcodedCredentials}/HardcodedCredentials.py | 0 .../HardcodedCredentials}/HardcodedCredentials.qhelp | 0 .../HardcodedCredentials}/HardcodedCredentials.ql | 0 .../IncompleteUrlSanitizer}/IncompleteHostnameRegExp.qhelp | 0 .../IncompleteUrlSanitizer}/IncompleteHostnameRegExp.ql | 0 .../IncompleteUrlSubstringSanitization.qhelp | 0 .../IncompleteUrlSubstringSanitization.ql | 0 .../examples/IncompleteHostnameRegExp.py | 0 .../examples/IncompleteUrlSubstringSanitization.py | 0 .../InsecureTemporaryFile}/InsecureTemporaryFile.py | 0 .../InsecureTemporaryFile}/InsecureTemporaryFile.qhelp | 0 .../InsecureTemporaryFile}/InsecureTemporaryFile.ql | 0 .../InsecureTemporaryFile}/SecureTemporaryFile.py | 0 .../Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.qhelp | 0 .../Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.ql | 0 .../Jinja2RenderWithoutEscape}/examples/jinja2.py | 0 .../SSHMissingHostKeyValidation.qhelp} | 0 .../SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql} | 0 .../SSHMissingHostKeyValidation}/examples/paramiko_host_key.py | 0 .../WeakFilePermissions}/WeakFilePermissions.qhelp | 0 .../WeakFilePermissions}/WeakFilePermissions.ql | 0 .../{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.qhelp | 0 .../Security/{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.ql | 0 .../src/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.qhelp | 0 .../ql/src/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.ql | 0 .../TLS}/examples/insecure_default_protocol.py | 0 .../{CWE-327 => Crypto/TLS}/examples/insecure_protocol.py | 0 .../WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp} | 2 +- .../WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql} | 0 .../WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py} | 0 .../WeakCryptoKey/WeakCryptoKey.qhelp} | 0 .../WeakCrypto.ql => Crypto/WeakCryptoKey/WeakCryptoKey.ql} | 0 .../SensitiveDataExposure}/CleartextLogging.qhelp | 0 .../SensitiveDataExposure}/CleartextLogging.ql | 0 .../SensitiveDataExposure}/CleartextStorage.qhelp | 0 .../SensitiveDataExposure}/CleartextStorage.ql | 0 .../SensitiveDataExposure}/examples/password_in_cookie.py | 0 .../StackTraceExposure}/StackTraceExposure.py | 0 .../StackTraceExposure}/StackTraceExposure.qhelp | 0 .../StackTraceExposure}/StackTraceExposure.ql | 0 .../{CWE-094 => Injection/CodeInjection}/CodeInjection.qhelp | 0 .../{CWE-094 => Injection/CodeInjection}/CodeInjection.ql | 0 .../CodeInjection}/examples/code_injection.py | 0 .../CommandInjection}/CommandInjection.qhelp | 0 .../{CWE-078 => Injection/CommandInjection}/CommandInjection.ql | 0 .../CommandInjection}/examples/command_injection.py | 0 .../OpenRedirect/OpenRedirect.qhelp} | 0 .../UrlRedirect.ql => Injection/OpenRedirect/OpenRedirect.ql} | 0 .../OpenRedirect}/examples/redirect_bad.py | 0 .../OpenRedirect}/examples/redirect_good.py | 0 .../{CWE-022 => Injection/PathInjection}/PathInjection.qhelp | 0 .../{CWE-022 => Injection/PathInjection}/PathInjection.ql | 0 .../PathInjection}/examples/tainted_path.py | 0 .../{CWE-079 => Injection/ReflectedXss}/ReflectedXss.qhelp | 0 .../{CWE-079 => Injection/ReflectedXss}/ReflectedXss.ql | 0 .../{CWE-079 => Injection/ReflectedXss}/examples/xss.py | 0 .../{CWE-089 => Injection/SqlInjection}/SqlInjection.qhelp | 0 .../{CWE-089 => Injection/SqlInjection}/SqlInjection.ql | 0 .../SqlInjection}/examples/sql_injection.py | 0 .../src/Security/{CWE-022 => Injection/TarSlip}/TarSlip.qhelp | 0 .../ql/src/Security/{CWE-022 => Injection/TarSlip}/TarSlip.ql | 0 .../{CWE-022 => Injection/TarSlip}/examples/tarslip_bad.py | 0 .../{CWE-022 => Injection/TarSlip}/examples/tarslip_good.py | 0 .../{CWE-502 => Injection/UnsafeDeserialization}/JsonGood.py | 0 .../UnsafeDeserialization}/UnpicklingBad.py | 0 .../UnsafeDeserialization}/UnsafeDeserialization.qhelp | 0 .../UnsafeDeserialization}/UnsafeDeserialization.ql | 0 83 files changed, 1 insertion(+), 1 deletion(-) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPISinkExample.py (100%) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPITaintStepExample.py (100%) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPIs.qll (100%) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.qhelp (100%) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.ql (100%) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/UntrustedDataToExternalAPI.qhelp (100%) rename python/ql/src/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/UntrustedDataToExternalAPI.ql (100%) rename python/ql/src/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/BindToAllInterfaces.py (100%) rename python/ql/src/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/BindToAllInterfaces.qhelp (100%) rename python/ql/src/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/BindToAllInterfaces.ql (100%) rename python/ql/src/Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.py (100%) rename python/ql/src/Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.qhelp (100%) rename python/ql/src/Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.ql (100%) rename python/ql/src/Security/{CWE-295/RequestWithoutValidation.qhelp => BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.qhelp} (100%) rename python/ql/src/Security/{CWE-295/RequestWithoutValidation.ql => BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql} (100%) rename python/ql/src/Security/{CWE-295 => BadPractice/HTTPSRequestWithoutCertValidation}/examples/make_request.py (100%) rename python/ql/src/Security/{CWE-798 => BadPractice/HardcodedCredentials}/HardcodedCredentials.py (100%) rename python/ql/src/Security/{CWE-798 => BadPractice/HardcodedCredentials}/HardcodedCredentials.qhelp (100%) rename python/ql/src/Security/{CWE-798 => BadPractice/HardcodedCredentials}/HardcodedCredentials.ql (100%) rename python/ql/src/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteHostnameRegExp.qhelp (100%) rename python/ql/src/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteHostnameRegExp.ql (100%) rename python/ql/src/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteUrlSubstringSanitization.qhelp (100%) rename python/ql/src/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteUrlSubstringSanitization.ql (100%) rename python/ql/src/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/examples/IncompleteHostnameRegExp.py (100%) rename python/ql/src/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/examples/IncompleteUrlSubstringSanitization.py (100%) rename python/ql/src/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/InsecureTemporaryFile.py (100%) rename python/ql/src/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/InsecureTemporaryFile.qhelp (100%) rename python/ql/src/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/InsecureTemporaryFile.ql (100%) rename python/ql/src/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/SecureTemporaryFile.py (100%) rename python/ql/src/Security/{CWE-079 => BadPractice/Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.qhelp (100%) rename python/ql/src/Security/{CWE-079 => BadPractice/Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.ql (100%) rename python/ql/src/Security/{CWE-079 => BadPractice/Jinja2RenderWithoutEscape}/examples/jinja2.py (100%) rename python/ql/src/Security/{CWE-295/MissingHostKeyValidation.qhelp => BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.qhelp} (100%) rename python/ql/src/Security/{CWE-295/MissingHostKeyValidation.ql => BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql} (100%) rename python/ql/src/Security/{CWE-295 => BadPractice/SSHMissingHostKeyValidation}/examples/paramiko_host_key.py (100%) rename python/ql/src/Security/{CWE-732 => BadPractice/WeakFilePermissions}/WeakFilePermissions.qhelp (100%) rename python/ql/src/Security/{CWE-732 => BadPractice/WeakFilePermissions}/WeakFilePermissions.ql (100%) rename python/ql/src/Security/{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.qhelp (100%) rename python/ql/src/Security/{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.ql (100%) rename python/ql/src/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.qhelp (100%) rename python/ql/src/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.ql (100%) rename python/ql/src/Security/{CWE-327 => Crypto/TLS}/examples/insecure_default_protocol.py (100%) rename python/ql/src/Security/{CWE-327 => Crypto/TLS}/examples/insecure_protocol.py (100%) rename python/ql/src/Security/{CWE-327/BrokenCryptoAlgorithm.qhelp => Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp} (97%) rename python/ql/src/Security/{CWE-327/BrokenCryptoAlgorithm.ql => Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql} (100%) rename python/ql/src/Security/{CWE-327/examples/broken_crypto.py => Crypto/WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py} (100%) rename python/ql/src/Security/{CWE-326/WeakCrypto.qhelp => Crypto/WeakCryptoKey/WeakCryptoKey.qhelp} (100%) rename python/ql/src/Security/{CWE-326/WeakCrypto.ql => Crypto/WeakCryptoKey/WeakCryptoKey.ql} (100%) rename python/ql/src/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextLogging.qhelp (100%) rename python/ql/src/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextLogging.ql (100%) rename python/ql/src/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextStorage.qhelp (100%) rename python/ql/src/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextStorage.ql (100%) rename python/ql/src/Security/{CWE-312 => Exposure/SensitiveDataExposure}/examples/password_in_cookie.py (100%) rename python/ql/src/Security/{CWE-209 => Exposure/StackTraceExposure}/StackTraceExposure.py (100%) rename python/ql/src/Security/{CWE-209 => Exposure/StackTraceExposure}/StackTraceExposure.qhelp (100%) rename python/ql/src/Security/{CWE-209 => Exposure/StackTraceExposure}/StackTraceExposure.ql (100%) rename python/ql/src/Security/{CWE-094 => Injection/CodeInjection}/CodeInjection.qhelp (100%) rename python/ql/src/Security/{CWE-094 => Injection/CodeInjection}/CodeInjection.ql (100%) rename python/ql/src/Security/{CWE-094 => Injection/CodeInjection}/examples/code_injection.py (100%) rename python/ql/src/Security/{CWE-078 => Injection/CommandInjection}/CommandInjection.qhelp (100%) rename python/ql/src/Security/{CWE-078 => Injection/CommandInjection}/CommandInjection.ql (100%) rename python/ql/src/Security/{CWE-078 => Injection/CommandInjection}/examples/command_injection.py (100%) rename python/ql/src/Security/{CWE-601/UrlRedirect.qhelp => Injection/OpenRedirect/OpenRedirect.qhelp} (100%) rename python/ql/src/Security/{CWE-601/UrlRedirect.ql => Injection/OpenRedirect/OpenRedirect.ql} (100%) rename python/ql/src/Security/{CWE-601 => Injection/OpenRedirect}/examples/redirect_bad.py (100%) rename python/ql/src/Security/{CWE-601 => Injection/OpenRedirect}/examples/redirect_good.py (100%) rename python/ql/src/Security/{CWE-022 => Injection/PathInjection}/PathInjection.qhelp (100%) rename python/ql/src/Security/{CWE-022 => Injection/PathInjection}/PathInjection.ql (100%) rename python/ql/src/Security/{CWE-022 => Injection/PathInjection}/examples/tainted_path.py (100%) rename python/ql/src/Security/{CWE-079 => Injection/ReflectedXss}/ReflectedXss.qhelp (100%) rename python/ql/src/Security/{CWE-079 => Injection/ReflectedXss}/ReflectedXss.ql (100%) rename python/ql/src/Security/{CWE-079 => Injection/ReflectedXss}/examples/xss.py (100%) rename python/ql/src/Security/{CWE-089 => Injection/SqlInjection}/SqlInjection.qhelp (100%) rename python/ql/src/Security/{CWE-089 => Injection/SqlInjection}/SqlInjection.ql (100%) rename python/ql/src/Security/{CWE-089 => Injection/SqlInjection}/examples/sql_injection.py (100%) rename python/ql/src/Security/{CWE-022 => Injection/TarSlip}/TarSlip.qhelp (100%) rename python/ql/src/Security/{CWE-022 => Injection/TarSlip}/TarSlip.ql (100%) rename python/ql/src/Security/{CWE-022 => Injection/TarSlip}/examples/tarslip_bad.py (100%) rename python/ql/src/Security/{CWE-022 => Injection/TarSlip}/examples/tarslip_good.py (100%) rename python/ql/src/Security/{CWE-502 => Injection/UnsafeDeserialization}/JsonGood.py (100%) rename python/ql/src/Security/{CWE-502 => Injection/UnsafeDeserialization}/UnpicklingBad.py (100%) rename python/ql/src/Security/{CWE-502 => Injection/UnsafeDeserialization}/UnsafeDeserialization.qhelp (100%) rename python/ql/src/Security/{CWE-502 => Injection/UnsafeDeserialization}/UnsafeDeserialization.ql (100%) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPISinkExample.py b/python/ql/src/POI/ExternalAPIs/ExternalAPISinkExample.py similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPISinkExample.py rename to python/ql/src/POI/ExternalAPIs/ExternalAPISinkExample.py diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPITaintStepExample.py b/python/ql/src/POI/ExternalAPIs/ExternalAPITaintStepExample.py similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPITaintStepExample.py rename to python/ql/src/POI/ExternalAPIs/ExternalAPITaintStepExample.py diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll rename to python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp b/python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp rename to python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql b/python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql rename to python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp b/python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.qhelp similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp rename to python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.qhelp diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql b/python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.ql similarity index 100% rename from python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql rename to python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py b/python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.py similarity index 100% rename from python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py rename to python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.py diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp b/python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qhelp similarity index 100% rename from python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp rename to python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qhelp diff --git a/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql b/python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql similarity index 100% rename from python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql rename to python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql diff --git a/python/ql/src/Security/CWE-215/FlaskDebug.py b/python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.py similarity index 100% rename from python/ql/src/Security/CWE-215/FlaskDebug.py rename to python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.py diff --git a/python/ql/src/Security/CWE-215/FlaskDebug.qhelp b/python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qhelp similarity index 100% rename from python/ql/src/Security/CWE-215/FlaskDebug.qhelp rename to python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qhelp diff --git a/python/ql/src/Security/CWE-215/FlaskDebug.ql b/python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.ql similarity index 100% rename from python/ql/src/Security/CWE-215/FlaskDebug.ql rename to python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.ql diff --git a/python/ql/src/Security/CWE-295/RequestWithoutValidation.qhelp b/python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.qhelp similarity index 100% rename from python/ql/src/Security/CWE-295/RequestWithoutValidation.qhelp rename to python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.qhelp diff --git a/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql b/python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql similarity index 100% rename from python/ql/src/Security/CWE-295/RequestWithoutValidation.ql rename to python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql diff --git a/python/ql/src/Security/CWE-295/examples/make_request.py b/python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/examples/make_request.py similarity index 100% rename from python/ql/src/Security/CWE-295/examples/make_request.py rename to python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/examples/make_request.py diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.py b/python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.py similarity index 100% rename from python/ql/src/Security/CWE-798/HardcodedCredentials.py rename to python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.py diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.qhelp b/python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qhelp similarity index 100% rename from python/ql/src/Security/CWE-798/HardcodedCredentials.qhelp rename to python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qhelp diff --git a/python/ql/src/Security/CWE-798/HardcodedCredentials.ql b/python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql similarity index 100% rename from python/ql/src/Security/CWE-798/HardcodedCredentials.ql rename to python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql diff --git a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp b/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qhelp similarity index 100% rename from python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp rename to python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qhelp diff --git a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql b/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql similarity index 100% rename from python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql rename to python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql diff --git a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp b/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qhelp similarity index 100% rename from python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp rename to python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qhelp diff --git a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql b/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql similarity index 100% rename from python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql rename to python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql diff --git a/python/ql/src/Security/CWE-020/examples/IncompleteHostnameRegExp.py b/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteHostnameRegExp.py similarity index 100% rename from python/ql/src/Security/CWE-020/examples/IncompleteHostnameRegExp.py rename to python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteHostnameRegExp.py diff --git a/python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py b/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteUrlSubstringSanitization.py similarity index 100% rename from python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py rename to python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteUrlSubstringSanitization.py diff --git a/python/ql/src/Security/CWE-377/InsecureTemporaryFile.py b/python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py similarity index 100% rename from python/ql/src/Security/CWE-377/InsecureTemporaryFile.py rename to python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py diff --git a/python/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp b/python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qhelp similarity index 100% rename from python/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp rename to python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qhelp diff --git a/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql b/python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.ql similarity index 100% rename from python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql rename to python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.ql diff --git a/python/ql/src/Security/CWE-377/SecureTemporaryFile.py b/python/ql/src/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py similarity index 100% rename from python/ql/src/Security/CWE-377/SecureTemporaryFile.py rename to python/ql/src/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp b/python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qhelp similarity index 100% rename from python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp rename to python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qhelp diff --git a/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql b/python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.ql similarity index 100% rename from python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql rename to python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.ql diff --git a/python/ql/src/Security/CWE-079/examples/jinja2.py b/python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/examples/jinja2.py similarity index 100% rename from python/ql/src/Security/CWE-079/examples/jinja2.py rename to python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/examples/jinja2.py diff --git a/python/ql/src/Security/CWE-295/MissingHostKeyValidation.qhelp b/python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.qhelp similarity index 100% rename from python/ql/src/Security/CWE-295/MissingHostKeyValidation.qhelp rename to python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.qhelp diff --git a/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql b/python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql similarity index 100% rename from python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql rename to python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql diff --git a/python/ql/src/Security/CWE-295/examples/paramiko_host_key.py b/python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/examples/paramiko_host_key.py similarity index 100% rename from python/ql/src/Security/CWE-295/examples/paramiko_host_key.py rename to python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/examples/paramiko_host_key.py diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp b/python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qhelp similarity index 100% rename from python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp rename to python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qhelp diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql b/python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.ql similarity index 100% rename from python/ql/src/Security/CWE-732/WeakFilePermissions.ql rename to python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.ql diff --git a/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.qhelp b/python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.qhelp similarity index 100% rename from python/ql/src/Security/CWE-327/InsecureDefaultProtocol.qhelp rename to python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.qhelp diff --git a/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql b/python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.ql similarity index 100% rename from python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql rename to python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.ql diff --git a/python/ql/src/Security/CWE-327/InsecureProtocol.qhelp b/python/ql/src/Security/Crypto/TLS/InsecureProtocol.qhelp similarity index 100% rename from python/ql/src/Security/CWE-327/InsecureProtocol.qhelp rename to python/ql/src/Security/Crypto/TLS/InsecureProtocol.qhelp diff --git a/python/ql/src/Security/CWE-327/InsecureProtocol.ql b/python/ql/src/Security/Crypto/TLS/InsecureProtocol.ql similarity index 100% rename from python/ql/src/Security/CWE-327/InsecureProtocol.ql rename to python/ql/src/Security/Crypto/TLS/InsecureProtocol.ql diff --git a/python/ql/src/Security/CWE-327/examples/insecure_default_protocol.py b/python/ql/src/Security/Crypto/TLS/examples/insecure_default_protocol.py similarity index 100% rename from python/ql/src/Security/CWE-327/examples/insecure_default_protocol.py rename to python/ql/src/Security/Crypto/TLS/examples/insecure_default_protocol.py diff --git a/python/ql/src/Security/CWE-327/examples/insecure_protocol.py b/python/ql/src/Security/Crypto/TLS/examples/insecure_protocol.py similarity index 100% rename from python/ql/src/Security/CWE-327/examples/insecure_protocol.py rename to python/ql/src/Security/Crypto/TLS/examples/insecure_protocol.py diff --git a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp b/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp similarity index 97% rename from python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp rename to python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp index ba5ab4d10c1..01c8460d14c 100644 --- a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp +++ b/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp @@ -36,7 +36,7 @@ example uses AES, which is a stronger modern algorithm.

    - +

    WARNING: Although the second example above is more robust, diff --git a/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql b/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql similarity index 100% rename from python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql rename to python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql diff --git a/python/ql/src/Security/CWE-327/examples/broken_crypto.py b/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py similarity index 100% rename from python/ql/src/Security/CWE-327/examples/broken_crypto.py rename to python/ql/src/Security/Crypto/WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py diff --git a/python/ql/src/Security/CWE-326/WeakCrypto.qhelp b/python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.qhelp similarity index 100% rename from python/ql/src/Security/CWE-326/WeakCrypto.qhelp rename to python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.qhelp diff --git a/python/ql/src/Security/CWE-326/WeakCrypto.ql b/python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.ql similarity index 100% rename from python/ql/src/Security/CWE-326/WeakCrypto.ql rename to python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.ql diff --git a/python/ql/src/Security/CWE-312/CleartextLogging.qhelp b/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.qhelp similarity index 100% rename from python/ql/src/Security/CWE-312/CleartextLogging.qhelp rename to python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.qhelp diff --git a/python/ql/src/Security/CWE-312/CleartextLogging.ql b/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.ql similarity index 100% rename from python/ql/src/Security/CWE-312/CleartextLogging.ql rename to python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.ql diff --git a/python/ql/src/Security/CWE-312/CleartextStorage.qhelp b/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.qhelp similarity index 100% rename from python/ql/src/Security/CWE-312/CleartextStorage.qhelp rename to python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.qhelp diff --git a/python/ql/src/Security/CWE-312/CleartextStorage.ql b/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.ql similarity index 100% rename from python/ql/src/Security/CWE-312/CleartextStorage.ql rename to python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.ql diff --git a/python/ql/src/Security/CWE-312/examples/password_in_cookie.py b/python/ql/src/Security/Exposure/SensitiveDataExposure/examples/password_in_cookie.py similarity index 100% rename from python/ql/src/Security/CWE-312/examples/password_in_cookie.py rename to python/ql/src/Security/Exposure/SensitiveDataExposure/examples/password_in_cookie.py diff --git a/python/ql/src/Security/CWE-209/StackTraceExposure.py b/python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.py similarity index 100% rename from python/ql/src/Security/CWE-209/StackTraceExposure.py rename to python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.py diff --git a/python/ql/src/Security/CWE-209/StackTraceExposure.qhelp b/python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.qhelp similarity index 100% rename from python/ql/src/Security/CWE-209/StackTraceExposure.qhelp rename to python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.qhelp diff --git a/python/ql/src/Security/CWE-209/StackTraceExposure.ql b/python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.ql similarity index 100% rename from python/ql/src/Security/CWE-209/StackTraceExposure.ql rename to python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.ql diff --git a/python/ql/src/Security/CWE-094/CodeInjection.qhelp b/python/ql/src/Security/Injection/CodeInjection/CodeInjection.qhelp similarity index 100% rename from python/ql/src/Security/CWE-094/CodeInjection.qhelp rename to python/ql/src/Security/Injection/CodeInjection/CodeInjection.qhelp diff --git a/python/ql/src/Security/CWE-094/CodeInjection.ql b/python/ql/src/Security/Injection/CodeInjection/CodeInjection.ql similarity index 100% rename from python/ql/src/Security/CWE-094/CodeInjection.ql rename to python/ql/src/Security/Injection/CodeInjection/CodeInjection.ql diff --git a/python/ql/src/Security/CWE-094/examples/code_injection.py b/python/ql/src/Security/Injection/CodeInjection/examples/code_injection.py similarity index 100% rename from python/ql/src/Security/CWE-094/examples/code_injection.py rename to python/ql/src/Security/Injection/CodeInjection/examples/code_injection.py diff --git a/python/ql/src/Security/CWE-078/CommandInjection.qhelp b/python/ql/src/Security/Injection/CommandInjection/CommandInjection.qhelp similarity index 100% rename from python/ql/src/Security/CWE-078/CommandInjection.qhelp rename to python/ql/src/Security/Injection/CommandInjection/CommandInjection.qhelp diff --git a/python/ql/src/Security/CWE-078/CommandInjection.ql b/python/ql/src/Security/Injection/CommandInjection/CommandInjection.ql similarity index 100% rename from python/ql/src/Security/CWE-078/CommandInjection.ql rename to python/ql/src/Security/Injection/CommandInjection/CommandInjection.ql diff --git a/python/ql/src/Security/CWE-078/examples/command_injection.py b/python/ql/src/Security/Injection/CommandInjection/examples/command_injection.py similarity index 100% rename from python/ql/src/Security/CWE-078/examples/command_injection.py rename to python/ql/src/Security/Injection/CommandInjection/examples/command_injection.py diff --git a/python/ql/src/Security/CWE-601/UrlRedirect.qhelp b/python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.qhelp similarity index 100% rename from python/ql/src/Security/CWE-601/UrlRedirect.qhelp rename to python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.qhelp diff --git a/python/ql/src/Security/CWE-601/UrlRedirect.ql b/python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.ql similarity index 100% rename from python/ql/src/Security/CWE-601/UrlRedirect.ql rename to python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.ql diff --git a/python/ql/src/Security/CWE-601/examples/redirect_bad.py b/python/ql/src/Security/Injection/OpenRedirect/examples/redirect_bad.py similarity index 100% rename from python/ql/src/Security/CWE-601/examples/redirect_bad.py rename to python/ql/src/Security/Injection/OpenRedirect/examples/redirect_bad.py diff --git a/python/ql/src/Security/CWE-601/examples/redirect_good.py b/python/ql/src/Security/Injection/OpenRedirect/examples/redirect_good.py similarity index 100% rename from python/ql/src/Security/CWE-601/examples/redirect_good.py rename to python/ql/src/Security/Injection/OpenRedirect/examples/redirect_good.py diff --git a/python/ql/src/Security/CWE-022/PathInjection.qhelp b/python/ql/src/Security/Injection/PathInjection/PathInjection.qhelp similarity index 100% rename from python/ql/src/Security/CWE-022/PathInjection.qhelp rename to python/ql/src/Security/Injection/PathInjection/PathInjection.qhelp diff --git a/python/ql/src/Security/CWE-022/PathInjection.ql b/python/ql/src/Security/Injection/PathInjection/PathInjection.ql similarity index 100% rename from python/ql/src/Security/CWE-022/PathInjection.ql rename to python/ql/src/Security/Injection/PathInjection/PathInjection.ql diff --git a/python/ql/src/Security/CWE-022/examples/tainted_path.py b/python/ql/src/Security/Injection/PathInjection/examples/tainted_path.py similarity index 100% rename from python/ql/src/Security/CWE-022/examples/tainted_path.py rename to python/ql/src/Security/Injection/PathInjection/examples/tainted_path.py diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.qhelp b/python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.qhelp similarity index 100% rename from python/ql/src/Security/CWE-079/ReflectedXss.qhelp rename to python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.qhelp diff --git a/python/ql/src/Security/CWE-079/ReflectedXss.ql b/python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.ql similarity index 100% rename from python/ql/src/Security/CWE-079/ReflectedXss.ql rename to python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.ql diff --git a/python/ql/src/Security/CWE-079/examples/xss.py b/python/ql/src/Security/Injection/ReflectedXss/examples/xss.py similarity index 100% rename from python/ql/src/Security/CWE-079/examples/xss.py rename to python/ql/src/Security/Injection/ReflectedXss/examples/xss.py diff --git a/python/ql/src/Security/CWE-089/SqlInjection.qhelp b/python/ql/src/Security/Injection/SqlInjection/SqlInjection.qhelp similarity index 100% rename from python/ql/src/Security/CWE-089/SqlInjection.qhelp rename to python/ql/src/Security/Injection/SqlInjection/SqlInjection.qhelp diff --git a/python/ql/src/Security/CWE-089/SqlInjection.ql b/python/ql/src/Security/Injection/SqlInjection/SqlInjection.ql similarity index 100% rename from python/ql/src/Security/CWE-089/SqlInjection.ql rename to python/ql/src/Security/Injection/SqlInjection/SqlInjection.ql diff --git a/python/ql/src/Security/CWE-089/examples/sql_injection.py b/python/ql/src/Security/Injection/SqlInjection/examples/sql_injection.py similarity index 100% rename from python/ql/src/Security/CWE-089/examples/sql_injection.py rename to python/ql/src/Security/Injection/SqlInjection/examples/sql_injection.py diff --git a/python/ql/src/Security/CWE-022/TarSlip.qhelp b/python/ql/src/Security/Injection/TarSlip/TarSlip.qhelp similarity index 100% rename from python/ql/src/Security/CWE-022/TarSlip.qhelp rename to python/ql/src/Security/Injection/TarSlip/TarSlip.qhelp diff --git a/python/ql/src/Security/CWE-022/TarSlip.ql b/python/ql/src/Security/Injection/TarSlip/TarSlip.ql similarity index 100% rename from python/ql/src/Security/CWE-022/TarSlip.ql rename to python/ql/src/Security/Injection/TarSlip/TarSlip.ql diff --git a/python/ql/src/Security/CWE-022/examples/tarslip_bad.py b/python/ql/src/Security/Injection/TarSlip/examples/tarslip_bad.py similarity index 100% rename from python/ql/src/Security/CWE-022/examples/tarslip_bad.py rename to python/ql/src/Security/Injection/TarSlip/examples/tarslip_bad.py diff --git a/python/ql/src/Security/CWE-022/examples/tarslip_good.py b/python/ql/src/Security/Injection/TarSlip/examples/tarslip_good.py similarity index 100% rename from python/ql/src/Security/CWE-022/examples/tarslip_good.py rename to python/ql/src/Security/Injection/TarSlip/examples/tarslip_good.py diff --git a/python/ql/src/Security/CWE-502/JsonGood.py b/python/ql/src/Security/Injection/UnsafeDeserialization/JsonGood.py similarity index 100% rename from python/ql/src/Security/CWE-502/JsonGood.py rename to python/ql/src/Security/Injection/UnsafeDeserialization/JsonGood.py diff --git a/python/ql/src/Security/CWE-502/UnpicklingBad.py b/python/ql/src/Security/Injection/UnsafeDeserialization/UnpicklingBad.py similarity index 100% rename from python/ql/src/Security/CWE-502/UnpicklingBad.py rename to python/ql/src/Security/Injection/UnsafeDeserialization/UnpicklingBad.py diff --git a/python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp b/python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qhelp similarity index 100% rename from python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp rename to python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qhelp diff --git a/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql b/python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.ql similarity index 100% rename from python/ql/src/Security/CWE-502/UnsafeDeserialization.ql rename to python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.ql From 1d6f9bee08373bdc89b07fba40de3941265e603f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Feb 2021 11:48:36 +0100 Subject: [PATCH 391/429] Python: Update qlrefs --- .../Security/CVE-2018-1281/BindToAllInterfaces.qlref | 2 +- .../ExternalAPIsUsedWithUntrustedData.qlref | 2 +- .../CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref | 2 +- .../query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref | 2 +- .../Security/CWE-020/IncompleteUrlSubstringSanitization.qlref | 2 +- .../Security/CWE-022-PathInjection/PathInjection.qlref | 2 +- .../ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref | 2 +- .../query-tests/Security/CWE-078-py2/CommandInjection.qlref | 2 +- .../ql/test/query-tests/Security/CWE-078/CommandInjection.qlref | 2 +- .../query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref | 2 +- python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref | 2 +- python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref | 2 +- python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref | 2 +- .../test/query-tests/Security/CWE-209/StackTraceExposure.qlref | 2 +- python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref | 2 +- .../query-tests/Security/CWE-295/MissingHostKeyValidation.qlref | 2 +- .../query-tests/Security/CWE-295/RequestWithoutValidation.qlref | 2 +- .../ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref | 2 +- .../ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref | 2 +- python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref | 2 +- .../query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref | 2 +- .../query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref | 2 +- .../ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref | 2 +- .../query-tests/Security/CWE-377/InsecureTemporaryFile.qlref | 2 +- .../query-tests/Security/CWE-502/UnsafeDeserialization.qlref | 2 +- python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref | 2 +- .../test/query-tests/Security/CWE-732/WeakFilePermissions.qlref | 2 +- .../query-tests/Security/CWE-798/HardcodedCredentials.qlref | 2 +- 28 files changed, 28 insertions(+), 28 deletions(-) diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref index f06cc3d869d..29aa18f4b41 100644 --- a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref @@ -1 +1 @@ -Security/CVE-2018-1281/BindToAllInterfaces.ql \ No newline at end of file +Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref index c91bf44f815..af8f30055eb 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref @@ -1 +1 @@ -Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql +POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref index 03c06feeec8..91c47f14b1c 100644 --- a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref @@ -1 +1 @@ -Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql +POI/ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref index e818d947252..7c132ddf232 100644 --- a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref +++ b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref @@ -1 +1 @@ -Security/CWE-020/IncompleteHostnameRegExp.ql \ No newline at end of file +Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref index 3fa6794419d..f41c8ec32d5 100644 --- a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref +++ b/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref @@ -1 +1 @@ -Security/CWE-020/IncompleteUrlSubstringSanitization.ql \ No newline at end of file +Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref index d43482cc509..510e08f427f 100644 --- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref @@ -1 +1 @@ -Security/CWE-022/PathInjection.ql +Security/Injection/PathInjection/PathInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref index cfede0c92b2..178cd6e0a8d 100644 --- a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref +++ b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref @@ -1 +1 @@ -Security/CWE-022/TarSlip.ql +Security/Injection/TarSlip/TarSlip.ql diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref index e38b88f2919..91951ea271b 100644 --- a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref @@ -1 +1 @@ -Security/CWE-078/CommandInjection.ql +Security/Injection/CommandInjection/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref index e38b88f2919..91951ea271b 100644 --- a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref @@ -1 +1 @@ -Security/CWE-078/CommandInjection.ql +Security/Injection/CommandInjection/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref b/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref index 9fefcf4a030..4cdcd0c5567 100644 --- a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref +++ b/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref @@ -1 +1 @@ -Security/CWE-079/Jinja2WithoutEscaping.ql +Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.ql diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref index e0efe102416..d92b3d701d5 100644 --- a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref +++ b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref @@ -1 +1 @@ -Security/CWE-079/ReflectedXss.ql +Security/Injection/ReflectedXss/ReflectedXss.ql diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref index d1d02cbe8d3..c2d12830195 100644 --- a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref @@ -1 +1 @@ -Security/CWE-089/SqlInjection.ql +Security/Injection/SqlInjection/SqlInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref index fe9adbf3b64..f912faeb71a 100644 --- a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref +++ b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref @@ -1 +1 @@ -Security/CWE-094/CodeInjection.ql +Security/Injection/CodeInjection/CodeInjection.ql diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref index 18cf2d49a1a..927502b954c 100644 --- a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref +++ b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref @@ -1 +1 @@ -Security/CWE-209/StackTraceExposure.ql +Security/Exposure/StackTraceExposure/StackTraceExposure.ql diff --git a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref b/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref index 0e21a3ac14f..67a0f7a60de 100644 --- a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref +++ b/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref @@ -1 +1 @@ -Security/CWE-215/FlaskDebug.ql +Security/BadPractice/FlaskRunWithDebug/FlaskDebug.ql diff --git a/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref b/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref index c366095516a..174098ffea7 100644 --- a/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref +++ b/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref @@ -1 +1 @@ -Security/CWE-295/MissingHostKeyValidation.ql +Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql diff --git a/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref b/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref index 7ad4d4d2ae3..c8e27ca0561 100644 --- a/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref +++ b/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref @@ -1 +1 @@ -Security/CWE-295/RequestWithoutValidation.ql +Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref b/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref index de9273391c8..176057d5c62 100644 --- a/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref +++ b/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref @@ -1 +1 @@ -Security/CWE-312/CleartextLogging.ql \ No newline at end of file +Security/Exposure/SensitiveDataExposure/CleartextLogging.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref b/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref index a32206e8d6a..1feacb96d8c 100644 --- a/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref +++ b/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref @@ -1 +1 @@ -Security/CWE-312/CleartextStorage.ql \ No newline at end of file +Security/Exposure/SensitiveDataExposure/CleartextStorage.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref b/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref index 75676139ac3..18cfd5a12bc 100644 --- a/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref +++ b/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref @@ -1 +1 @@ -Security/CWE-326/WeakCrypto.ql +Security/Crypto/WeakCryptoKey/WeakCryptoKey.ql diff --git a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref index 3f7aff53700..4fb0ce84c4d 100644 --- a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref +++ b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref @@ -1 +1 @@ -Security/CWE-327/BrokenCryptoAlgorithm.ql +Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref index 13599b14931..899586366e8 100644 --- a/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref +++ b/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref @@ -1 +1 @@ -Security/CWE-327/InsecureDefaultProtocol.ql +Security/Crypto/TLS/InsecureDefaultProtocol.ql diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref index c06a937ff57..8225a5c47ef 100644 --- a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref +++ b/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref @@ -1 +1 @@ -Security/CWE-327/InsecureProtocol.ql +Security/Crypto/TLS/InsecureProtocol.ql diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref b/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref index 68a27dfb269..ee6d466921c 100644 --- a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref +++ b/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref @@ -1 +1 @@ -Security/CWE-377/InsecureTemporaryFile.ql +Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.ql diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref index fa9c0ceb3cb..49f13932a15 100644 --- a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref +++ b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref @@ -1 +1 @@ -Security/CWE-502/UnsafeDeserialization.ql +Security/Injection/UnsafeDeserialization/UnsafeDeserialization.ql diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref index 8b63d80f0db..ce10eb1f21a 100644 --- a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref @@ -1,2 +1,2 @@ -Security/CWE-601/UrlRedirect.ql +Security/Injection/OpenRedirect/OpenRedirect.ql diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref index 9e177187c49..8a8619a4a2d 100644 --- a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref @@ -1 +1 @@ -Security/CWE-732/WeakFilePermissions.ql +Security/BadPractice/WeakFilePermissions/WeakFilePermissions.ql diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref index 0d0fafa271c..9ced1d74449 100644 --- a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref +++ b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref @@ -1 +1 @@ -Security/CWE-798/HardcodedCredentials.ql \ No newline at end of file +Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql \ No newline at end of file From 86268d49ed9749a68db6a7e35d96268d0c31885b Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 11:10:57 +0000 Subject: [PATCH 392/429] C++: Refactor StdContainer.qll. --- .../models/implementations/StdContainer.qll | 117 ++++++++++++++++-- 1 file changed, 105 insertions(+), 12 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll index e7abde30e8c..497d828fd03 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -5,6 +5,41 @@ import semmle.code.cpp.models.interfaces.Taint import semmle.code.cpp.models.interfaces.Iterator +/** + * The `std::array` template class. + */ +private class Array extends Class { + Array() { this.hasQualifiedName(["std", "bsl"], "array") } +} + +/** + * The `std::deque` template class. + */ +private class Deque extends Class { + Deque() { this.hasQualifiedName(["std", "bsl"], "deque") } +} + +/** + * The `std::forward_list` template class. + */ +private class ForwardList extends Class { + ForwardList() { this.hasQualifiedName(["std", "bsl"], "forward_list") } +} + +/** + * The `std::list` template class. + */ +private class List extends Class { + List() { this.hasQualifiedName(["std", "bsl"], "list") } +} + +/** + * The `std::vector` template class. + */ +private class Vector extends Class { + Vector() { this.hasQualifiedName(["std", "bsl"], "vector") } +} + /** * Additional model for standard container constructors that reference the * value type of the container (that is, the `T` in `std::vector`). For @@ -15,7 +50,10 @@ import semmle.code.cpp.models.interfaces.Iterator */ private class StdSequenceContainerConstructor extends Constructor, TaintFunction { StdSequenceContainerConstructor() { - this.getDeclaringType().hasQualifiedName("std", ["vector", "deque", "list", "forward_list"]) + this.getDeclaringType() instanceof Vector or + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof List or + this.getDeclaringType() instanceof ForwardList } /** @@ -50,7 +88,13 @@ private class StdSequenceContainerConstructor extends Constructor, TaintFunction * The standard container function `data`. */ private class StdSequenceContainerData extends TaintFunction { - StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") } + StdSequenceContainerData() { + this.hasName("data") and + ( + this.getDeclaringType() instanceof Vector or + this.getDeclaringType() instanceof Array + ) + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from container itself (qualifier) to return value @@ -69,8 +113,19 @@ private class StdSequenceContainerData extends TaintFunction { */ private class StdSequenceContainerPush extends TaintFunction { StdSequenceContainerPush() { - this.hasQualifiedName("std", ["vector", "deque", "list"], "push_back") or - this.hasQualifiedName("std", ["deque", "list", "forward_list"], "push_front") + this.hasName("push_back") and + ( + this.getDeclaringType() instanceof Array or + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof List + ) + or + this.hasName("push_front") and + ( + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof ForwardList or + this.getDeclaringType() instanceof List + ) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -85,8 +140,22 @@ private class StdSequenceContainerPush extends TaintFunction { */ private class StdSequenceContainerFrontBack extends TaintFunction { StdSequenceContainerFrontBack() { - this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "front") or - this.hasQualifiedName("std", ["array", "vector", "deque", "list"], "back") + this.hasName("front") and + ( + this.getDeclaringType() instanceof Array or + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof ForwardList or + this.getDeclaringType() instanceof List or + this.getDeclaringType() instanceof Vector + ) + or + this.hasName("back") and + ( + this.getDeclaringType() instanceof Array or + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof List or + this.getDeclaringType() instanceof Vector + ) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -101,8 +170,15 @@ private class StdSequenceContainerFrontBack extends TaintFunction { */ private class StdSequenceContainerInsert extends TaintFunction { StdSequenceContainerInsert() { - this.hasQualifiedName("std", ["vector", "deque", "list"], "insert") or - this.hasQualifiedName("std", "forward_list", "insert_after") + this.hasName("insert") and + ( + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof List or + this.getDeclaringType() instanceof Vector + ) + or + this.hasName("insert_after") and + this.getDeclaringType() instanceof ForwardList } /** @@ -138,7 +214,13 @@ private class StdSequenceContainerInsert extends TaintFunction { */ private class StdSequenceContainerAssign extends TaintFunction { StdSequenceContainerAssign() { - this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign") + this.hasName("assign") and + ( + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof ForwardList or + this.getDeclaringType() instanceof List or + this.getDeclaringType() instanceof Vector + ) } /** @@ -170,7 +252,12 @@ private class StdSequenceContainerAssign extends TaintFunction { */ private class StdSequenceContainerAt extends TaintFunction { StdSequenceContainerAt() { - this.hasQualifiedName("std", ["vector", "array", "deque"], ["at", "operator[]"]) + this.hasName(["at", "operator[]"]) and + ( + this.getDeclaringType() instanceof Array or + this.getDeclaringType() instanceof Deque or + this.getDeclaringType() instanceof Vector + ) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -188,7 +275,10 @@ private class StdSequenceContainerAt extends TaintFunction { * The standard vector `emplace` function. */ class StdVectorEmplace extends TaintFunction { - StdVectorEmplace() { this.hasQualifiedName("std", "vector", "emplace") } + StdVectorEmplace() { + this.hasName("emplace") and + this.getDeclaringType() instanceof Vector + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter except the position iterator to qualifier and return value @@ -205,7 +295,10 @@ class StdVectorEmplace extends TaintFunction { * The standard vector `emplace_back` function. */ class StdVectorEmplaceBack extends TaintFunction { - StdVectorEmplaceBack() { this.hasQualifiedName("std", "vector", "emplace_back") } + StdVectorEmplaceBack() { + this.hasName("emplace_back") and + this.getDeclaringType() instanceof Vector + } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier From b25f1fd44acf9fc677beb4065f13917d6aa8e5d6 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 11:37:43 +0000 Subject: [PATCH 393/429] C++: Address review. --- .../models/implementations/StdContainer.qll | 88 +++++-------------- 1 file changed, 24 insertions(+), 64 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll index 497d828fd03..f416d8e9810 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -89,11 +89,8 @@ private class StdSequenceContainerConstructor extends Constructor, TaintFunction */ private class StdSequenceContainerData extends TaintFunction { StdSequenceContainerData() { - this.hasName("data") and - ( - this.getDeclaringType() instanceof Vector or - this.getDeclaringType() instanceof Array - ) + this.getClassAndName("data") instanceof Array or + this.getClassAndName("data") instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -113,19 +110,10 @@ private class StdSequenceContainerData extends TaintFunction { */ private class StdSequenceContainerPush extends TaintFunction { StdSequenceContainerPush() { - this.hasName("push_back") and - ( - this.getDeclaringType() instanceof Array or - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof List - ) - or - this.hasName("push_front") and - ( - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof ForwardList or - this.getDeclaringType() instanceof List - ) + this.getClassAndName("push_back") instanceof Array or + this.getClassAndName(["push_back", "push_front"]) instanceof Deque or + this.getClassAndName("push_front") instanceof ForwardList or + this.getClassAndName("push_back") instanceof List or } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -140,22 +128,11 @@ private class StdSequenceContainerPush extends TaintFunction { */ private class StdSequenceContainerFrontBack extends TaintFunction { StdSequenceContainerFrontBack() { - this.hasName("front") and - ( - this.getDeclaringType() instanceof Array or - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof ForwardList or - this.getDeclaringType() instanceof List or - this.getDeclaringType() instanceof Vector - ) - or - this.hasName("back") and - ( - this.getDeclaringType() instanceof Array or - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof List or - this.getDeclaringType() instanceof Vector - ) + this.getClassAndName(["front", "back"]) instanceof Array or + this.getClassAndName(["front", "back"]) instanceof Deque or + this.getClassAndName("front") instanceof ForwardList or + this.getClassAndName(["front", "back"]) instanceof List or + this.getClassAndName(["front", "back"]) instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -170,15 +147,10 @@ private class StdSequenceContainerFrontBack extends TaintFunction { */ private class StdSequenceContainerInsert extends TaintFunction { StdSequenceContainerInsert() { - this.hasName("insert") and - ( - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof List or - this.getDeclaringType() instanceof Vector - ) - or - this.hasName("insert_after") and - this.getDeclaringType() instanceof ForwardList + this.getClassAndName("insert") instanceof Deque or + this.getClassAndName("insert") instanceof List or + this.getClassAndName("insert") instanceof Vector or + this.getClassAndName("insert_after") instanceof ForwardList } /** @@ -214,13 +186,10 @@ private class StdSequenceContainerInsert extends TaintFunction { */ private class StdSequenceContainerAssign extends TaintFunction { StdSequenceContainerAssign() { - this.hasName("assign") and - ( - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof ForwardList or - this.getDeclaringType() instanceof List or - this.getDeclaringType() instanceof Vector - ) + this.getClassAndName("assign") instanceof Deque or + this.getClassAndName("assign") instanceof ForwardList or + this.getClassAndName("assign") instanceof List or + this.getClassAndName("assign") instanceof Vector } /** @@ -252,12 +221,9 @@ private class StdSequenceContainerAssign extends TaintFunction { */ private class StdSequenceContainerAt extends TaintFunction { StdSequenceContainerAt() { - this.hasName(["at", "operator[]"]) and - ( - this.getDeclaringType() instanceof Array or - this.getDeclaringType() instanceof Deque or - this.getDeclaringType() instanceof Vector - ) + this.getClassAndName(["at", "operator[]"]) instanceof Array or + this.getClassAndName(["at", "operator[]"]) instanceof Deque or + this.getClassAndName(["at", "operator[]"]) instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -275,10 +241,7 @@ private class StdSequenceContainerAt extends TaintFunction { * The standard vector `emplace` function. */ class StdVectorEmplace extends TaintFunction { - StdVectorEmplace() { - this.hasName("emplace") and - this.getDeclaringType() instanceof Vector - } + StdVectorEmplace() { this.getClassAndName("emplace") instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter except the position iterator to qualifier and return value @@ -295,10 +258,7 @@ class StdVectorEmplace extends TaintFunction { * The standard vector `emplace_back` function. */ class StdVectorEmplaceBack extends TaintFunction { - StdVectorEmplaceBack() { - this.hasName("emplace_back") and - this.getDeclaringType() instanceof Vector - } + StdVectorEmplaceBack() { this.getClassAndName("emplace_back") instanceof Vector } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter to qualifier From 5dc57e9cc297e57aaa0ba829f9ee575e71b974c6 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 11:49:44 +0000 Subject: [PATCH 394/429] C++: Address review. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 4 ++-- .../src/semmle/code/cpp/models/implementations/Pure.qll | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 1f488bfeb5f..7ac79fd99c1 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -142,9 +142,9 @@ class Declaration extends Locatable, @declaration { /** * Holds if this declaration has the given name in the global namespace, * the `std` namespace or the `bsl` namespace. - * We treat `std` and `bsl` as the same in a bunch of our models. + * We treat `std` and `bsl` as the same in some of our models. */ - predicate hasGlobalOrStdishName(string name) { + predicate hasGlobalOrStdOrBslName(string name) { this.hasGlobalName(name) or this.hasQualifiedName("std", "", name) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll index 4682032f284..d81ac80deb8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Pure.qll @@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.SideEffect private class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureStrFunction() { - hasGlobalOrStdishName([ + hasGlobalOrStdOrBslName([ atoi(), "strcasestr", "strchnul", "strchr", "strchrnul", "strstr", "strpbrk", "strrchr", "strspn", strtol(), strrev(), strcmp(), strlwr(), strupr() ]) @@ -92,7 +92,7 @@ private string strcmp() { /** String standard `strlen` function, and related functions for computing string lengths. */ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFunction { StrLenFunction() { - hasGlobalOrStdishName(["strlen", "strnlen", "wcslen"]) + hasGlobalOrStdOrBslName(["strlen", "strnlen", "wcslen"]) or hasGlobalName(["_mbslen", "_mbslen_l", "_mbstrlen", "_mbstrlen_l"]) } @@ -125,7 +125,7 @@ private class StrLenFunction extends AliasFunction, ArrayFunction, SideEffectFun /** Pure functions. */ private class PureFunction extends TaintFunction, SideEffectFunction { - PureFunction() { hasGlobalOrStdishName(["abs", "labs"]) } + PureFunction() { hasGlobalOrStdOrBslName(["abs", "labs"]) } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { exists(ParameterIndex i | @@ -144,7 +144,7 @@ private class PureFunction extends TaintFunction, SideEffectFunction { private class PureMemFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction { PureMemFunction() { - hasGlobalOrStdishName([ + hasGlobalOrStdOrBslName([ "memchr", "__builtin_memchr", "memrchr", "rawmemchr", "memcmp", "__builtin_memcmp", "memmem" ]) or this.hasGlobalName("memfrob") From a42700f09e96d479941d58acdc4d95338d816dc9 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 11:52:39 +0000 Subject: [PATCH 395/429] C++: Address review. --- .../cpp/models/implementations/StdMap.qll | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll index 6925fb110fc..ae3fab9f077 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll @@ -41,8 +41,7 @@ private class StdMapConstructor extends Constructor, TaintFunction { */ private class StdMapInsert extends TaintFunction { StdMapInsert() { - this.hasName(["insert", "insert_or_assign"]) and - this.getDeclaringType() instanceof MapOrUnorderedMap + this.getClassAndName(["insert", "insert_or_assign"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -60,10 +59,7 @@ private class StdMapInsert extends TaintFunction { * The standard map `emplace` and `emplace_hint` functions. */ private class StdMapEmplace extends TaintFunction { - StdMapEmplace() { - this.hasName(["emplace", "emplace_hint"]) and - this.getDeclaringType() instanceof MapOrUnorderedMap - } + StdMapEmplace() { this.getClassAndName(["emplace", "emplace_hint"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from the last parameter (which may be the value part used to @@ -85,10 +81,7 @@ private class StdMapEmplace extends TaintFunction { * The standard map `try_emplace` function. */ private class StdMapTryEmplace extends TaintFunction { - StdMapTryEmplace() { - this.hasName("try_emplace") and - this.getDeclaringType() instanceof MapOrUnorderedMap - } + StdMapTryEmplace() { this.getClassAndName("try_emplace") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from any parameter apart from the key to qualifier and return value @@ -115,10 +108,7 @@ private class StdMapTryEmplace extends TaintFunction { * The standard map `merge` function. */ private class StdMapMerge extends TaintFunction { - StdMapMerge() { - this.hasName("merge") and - this.getDeclaringType() instanceof MapOrUnorderedMap - } + StdMapMerge() { this.getClassAndName("merge") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // container1.merge(container2) @@ -131,10 +121,7 @@ private class StdMapMerge extends TaintFunction { * The standard map functions `at` and `operator[]`. */ private class StdMapAt extends TaintFunction { - StdMapAt() { - this.hasName(["at", "operator[]"]) and - this.getDeclaringType() instanceof MapOrUnorderedMap - } + StdMapAt() { this.getClassAndName(["at", "operator[]"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to referenced return value @@ -151,10 +138,7 @@ private class StdMapAt extends TaintFunction { * The standard map `find` function. */ private class StdMapFind extends TaintFunction { - StdMapFind() { - this.hasName("find") and - this.getDeclaringType() instanceof MapOrUnorderedMap - } + StdMapFind() { this.getClassAndName("find") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { input.isQualifierObject() and @@ -166,10 +150,7 @@ private class StdMapFind extends TaintFunction { * The standard map `erase` function. */ private class StdMapErase extends TaintFunction { - StdMapErase() { - this.hasName("erase") and - this.getDeclaringType() instanceof MapOrUnorderedMap - } + StdMapErase() { this.getCLassAndName("erase") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value From 30659f3ecf7ae2ecf9c470b51c6ea464d9b1f729 Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 11:54:21 +0000 Subject: [PATCH 396/429] C++: Address review. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 4 ++-- cpp/ql/src/semmle/code/cpp/commons/Scanf.qll | 12 ++++++------ .../code/cpp/models/implementations/Printf.qll | 8 ++++---- .../code/cpp/models/implementations/Strcat.qll | 2 +- .../code/cpp/models/implementations/Strcpy.qll | 2 +- .../code/cpp/models/implementations/Strtok.qll | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 1f488bfeb5f..7ac79fd99c1 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -142,9 +142,9 @@ class Declaration extends Locatable, @declaration { /** * Holds if this declaration has the given name in the global namespace, * the `std` namespace or the `bsl` namespace. - * We treat `std` and `bsl` as the same in a bunch of our models. + * We treat `std` and `bsl` as the same in some of our models. */ - predicate hasGlobalOrStdishName(string name) { + predicate hasGlobalOrStdOrBslName(string name) { this.hasGlobalName(name) or this.hasQualifiedName("std", "", name) diff --git a/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll b/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll index aec047cea6b..461030f389d 100644 --- a/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll +++ b/cpp/ql/src/semmle/code/cpp/commons/Scanf.qll @@ -34,8 +34,8 @@ class Scanf extends ScanfFunction { Scanf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName("scanf") or // scanf(format, args...) - hasGlobalOrStdishName("wscanf") or // wscanf(format, args...) + hasGlobalOrStdOrBslName("scanf") or // scanf(format, args...) + hasGlobalOrStdOrBslName("wscanf") or // wscanf(format, args...) hasGlobalName("_scanf_l") or // _scanf_l(format, locale, args...) hasGlobalName("_wscanf_l") // _wscanf_l(format, locale, args...) ) @@ -53,8 +53,8 @@ class Fscanf extends ScanfFunction { Fscanf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName("fscanf") or // fscanf(src_stream, format, args...) - hasGlobalOrStdishName("fwscanf") or // fwscanf(src_stream, format, args...) + hasGlobalOrStdOrBslName("fscanf") or // fscanf(src_stream, format, args...) + hasGlobalOrStdOrBslName("fwscanf") or // fwscanf(src_stream, format, args...) hasGlobalName("_fscanf_l") or // _fscanf_l(src_stream, format, locale, args...) hasGlobalName("_fwscanf_l") // _fwscanf_l(src_stream, format, locale, args...) ) @@ -72,8 +72,8 @@ class Sscanf extends ScanfFunction { Sscanf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName("sscanf") or // sscanf(src_stream, format, args...) - hasGlobalOrStdishName("swscanf") or // swscanf(src, format, args...) + hasGlobalOrStdOrBslName("sscanf") or // sscanf(src_stream, format, args...) + hasGlobalOrStdOrBslName("swscanf") or // swscanf(src, format, args...) hasGlobalName("_sscanf_l") or // _sscanf_l(src, format, locale, args...) hasGlobalName("_swscanf_l") // _swscanf_l(src, format, locale, args...) ) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll index f70493e9f83..ed201a14587 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Printf.qll @@ -15,7 +15,7 @@ private class Printf extends FormattingFunction, AliasFunction { Printf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName(["printf", "wprintf"]) or + hasGlobalOrStdOrBslName(["printf", "wprintf"]) or hasGlobalName(["printf_s", "wprintf_s", "g_printf"]) ) and not exists(getDefinition().getFile().getRelativePath()) @@ -41,7 +41,7 @@ private class Fprintf extends FormattingFunction { Fprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName(["fprintf", "fwprintf"]) or + hasGlobalOrStdOrBslName(["fprintf", "fwprintf"]) or hasGlobalName("g_fprintf") ) and not exists(getDefinition().getFile().getRelativePath()) @@ -61,7 +61,7 @@ private class Sprintf extends FormattingFunction { Sprintf() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName([ + hasGlobalOrStdOrBslName([ "sprintf", // sprintf(dst, format, args...) "wsprintf" // wsprintf(dst, format, args...) ]) @@ -111,7 +111,7 @@ private class SnprintfImpl extends Snprintf { SnprintfImpl() { this instanceof TopLevelFunction and ( - hasGlobalOrStdishName([ + hasGlobalOrStdOrBslName([ "snprintf", // C99 defines snprintf "swprintf" // The s version of wide-char printf is also always the n version ]) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll index 6dbed650cfa..ee9af547582 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcat.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction { StrcatFunction() { - this.hasGlobalOrStdishName([ + this.hasGlobalOrStdOrBslName([ "strcat", // strcat(dst, src) "strncat", // strncat(dst, src, max_amount) "wcscat", // wcscat(dst, src) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll index 72f993b7a4a..432fbf999ef 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strcpy.qll @@ -13,7 +13,7 @@ import semmle.code.cpp.models.interfaces.SideEffect */ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction { StrcpyFunction() { - this.hasGlobalOrStdishName([ + this.hasGlobalOrStdOrBslName([ "strcpy", // strcpy(dst, src) "wcscpy", // wcscpy(dst, src) "strncpy", // strncpy(dst, src, max_amount) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll index 3b7e97a53d0..f2cb6498819 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strtok.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.Taint */ private class Strtok extends ArrayFunction, AliasFunction, TaintFunction, SideEffectFunction { Strtok() { - this.hasGlobalOrStdishName("strtok") or + this.hasGlobalOrStdOrBslName("strtok") or this.hasGlobalName(["strtok_r", "_strtok_l", "wcstok", "_wcstok_l", "_mbstok", "_mbstok_l"]) } From 3f17171f13d33fc7d0ddbfefd4f0ef12014e57be Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 11:55:03 +0000 Subject: [PATCH 397/429] C++: Address review. --- cpp/ql/src/semmle/code/cpp/Declaration.qll | 4 ++-- cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Declaration.qll b/cpp/ql/src/semmle/code/cpp/Declaration.qll index 1f488bfeb5f..7ac79fd99c1 100644 --- a/cpp/ql/src/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/src/semmle/code/cpp/Declaration.qll @@ -142,9 +142,9 @@ class Declaration extends Locatable, @declaration { /** * Holds if this declaration has the given name in the global namespace, * the `std` namespace or the `bsl` namespace. - * We treat `std` and `bsl` as the same in a bunch of our models. + * We treat `std` and `bsl` as the same in some of our models. */ - predicate hasGlobalOrStdishName(string name) { + predicate hasGlobalOrStdOrBslName(string name) { this.hasGlobalName(name) or this.hasQualifiedName("std", "", name) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll index 5e3f446713f..d646be0363d 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Memset.qll @@ -15,7 +15,7 @@ import semmle.code.cpp.models.interfaces.SideEffect private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction, SideEffectFunction { MemsetFunction() { - this.hasGlobalOrStdishName("memset") + this.hasGlobalOrStdOrBslName("memset") or this.hasGlobalOrStdName("wmemset") or From 8494fcf45fcb7c21abbd5640cc28106b85afc653 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Feb 2021 13:15:01 +0100 Subject: [PATCH 398/429] Python: Move query tests to reflect new file layout --- .../ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.expected | 0 .../ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.qlref | 0 .../ExternalAPIs}/UntrustedDataToExternalAPI.expected | 0 .../ExternalAPIs}/UntrustedDataToExternalAPI.qlref | 0 .../{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/test.py | 0 .../BindToAllInterfaces}/BindToAllInterfaces.expected | 0 .../BindToAllInterfaces}/BindToAllInterfaces.qlref | 0 .../BindToAllInterfaces}/BindToAllInterfaces_test.py | 0 .../{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/options | 0 .../FlaskRunWithDebug}/FlaskDebug.expected | 0 .../{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.qlref | 0 .../query-tests/Security/BadPractice/FlaskRunWithDebug/options | 1 + .../Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/test.py | 0 .../RequestWithoutValidation.expected | 0 .../RequestWithoutValidation.qlref | 0 .../HTTPSRequestWithoutCertValidation}/make_request.py | 0 .../BadPractice/HTTPSRequestWithoutCertValidation/options | 1 + .../HardcodedCredentials}/HardcodedCredentials.expected | 0 .../HardcodedCredentials}/HardcodedCredentials.qlref | 0 .../{CWE-798 => BadPractice/HardcodedCredentials}/test.py | 0 .../IncompleteUrlSanitizer}/IncompleteHostnameRegExp.expected | 0 .../IncompleteUrlSanitizer}/IncompleteHostnameRegExp.qlref | 0 .../IncompleteUrlSubstringSanitization.expected | 0 .../IncompleteUrlSubstringSanitization.qlref | 0 .../{CWE-020 => BadPractice/IncompleteUrlSanitizer}/hosttest.py | 0 .../{CWE-020 => BadPractice/IncompleteUrlSanitizer}/urltest.py | 0 .../InsecureTemporaryFile}/InsecureTemporaryFile.expected | 0 .../InsecureTemporaryFile}/InsecureTemporaryFile.py | 0 .../InsecureTemporaryFile}/InsecureTemporaryFile.qlref | 0 .../InsecureTemporaryFile}/SecureTemporaryFile.py | 0 .../Security/BadPractice/InsecureTemporaryFile/options | 1 + .../Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.expected | 0 .../Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.qlref | 0 .../Jinja2RenderWithoutEscape}/jinja2_escaping.py | 0 .../Jinja2RenderWithoutEscape}/options | 0 .../MissingHostKeyValidation.expected | 0 .../SSHMissingHostKeyValidation}/MissingHostKeyValidation.qlref | 0 .../Security/BadPractice/SSHMissingHostKeyValidation/options | 1 + .../SSHMissingHostKeyValidation}/paramiko_host_key.py | 0 .../WeakFilePermissions}/WeakFilePermissions.expected | 0 .../WeakFilePermissions}/WeakFilePermissions.qlref | 0 .../query-tests/Security/BadPractice/WeakFilePermissions/options | 1 + .../{CWE-732 => BadPractice/WeakFilePermissions}/test.py | 0 python/ql/test/query-tests/Security/CWE-079/options | 1 - python/ql/test/query-tests/Security/CWE-209/options | 1 - python/ql/test/query-tests/Security/CWE-215/options | 1 - python/ql/test/query-tests/Security/CWE-295/options | 1 - python/ql/test/query-tests/Security/CWE-312/options | 1 - python/ql/test/query-tests/Security/CWE-326/options | 1 - python/ql/test/query-tests/Security/CWE-327/options | 1 - python/ql/test/query-tests/Security/CWE-377/options | 1 - python/ql/test/query-tests/Security/CWE-601/options | 1 - python/ql/test/query-tests/Security/CWE-732/options | 1 - .../{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.expected | 0 .../{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.qlref | 0 .../Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.expected | 0 .../Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.py | 0 .../Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.qlref | 0 python/ql/test/query-tests/Security/Crypto/TLS/options | 1 + .../WeakCryptoAlgorithm}/BrokenCryptoAlgorithm.expected | 0 .../WeakCryptoAlgorithm}/BrokenCryptoAlgorithm.qlref | 0 .../{CWE-327 => Crypto/WeakCryptoAlgorithm}/TestNode.expected | 0 .../Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/TestNode.ql | 0 .../test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options | 1 + .../{CWE-327 => Crypto/WeakCryptoAlgorithm}/test_cryptography.py | 0 .../{CWE-327 => Crypto/WeakCryptoAlgorithm}/test_pycrypto.py | 0 .../{CWE-326 => Crypto/WeakCryptoKey}/WeakCrypto.expected | 0 .../Security/{CWE-326 => Crypto/WeakCryptoKey}/WeakCrypto.qlref | 0 python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options | 1 + .../Security/{CWE-326 => Crypto/WeakCryptoKey}/weak_crypto.py | 0 .../SensitiveDataExposure}/CleartextLogging.expected | 0 .../SensitiveDataExposure}/CleartextLogging.qlref | 0 .../SensitiveDataExposure}/CleartextStorage.expected | 0 .../SensitiveDataExposure}/CleartextStorage.qlref | 0 .../query-tests/Security/Exposure/SensitiveDataExposure/options | 1 + .../SensitiveDataExposure}/password_in_cookie.py | 0 .../Security/{CWE-312 => Exposure/SensitiveDataExposure}/test.py | 0 .../StackTraceExposure}/StackTraceExposure.expected | 0 .../StackTraceExposure}/StackTraceExposure.qlref | 0 .../query-tests/Security/Exposure/StackTraceExposure/options | 1 + .../Security/{CWE-209 => Exposure/StackTraceExposure}/test.py | 0 .../{CWE-094 => Injection/CodeInjection}/CodeInjection.expected | 0 .../{CWE-094 => Injection/CodeInjection}/CodeInjection.qlref | 0 .../{CWE-094 => Injection/CodeInjection}/code_injection.py | 0 .../CommandInjection-py2}/CommandInjection.expected | 0 .../CommandInjection-py2}/CommandInjection.qlref | 0 .../CommandInjection-py2}/command_injection.py | 0 .../{CWE-078-py2 => Injection/CommandInjection-py2}/options | 0 .../CommandInjection}/CommandInjection.expected | 0 .../CommandInjection}/CommandInjection.qlref | 0 .../{CWE-078 => Injection/CommandInjection}/command_injection.py | 0 .../Security/{CWE-078 => Injection/CommandInjection}/options | 0 .../{CWE-601 => Injection/OpenRedirect}/UrlRedirect.expected | 0 .../{CWE-601 => Injection/OpenRedirect}/UrlRedirect.qlref | 0 .../ql/test/query-tests/Security/Injection/OpenRedirect/options | 1 + .../Security/{CWE-601 => Injection/OpenRedirect}/test.py | 0 .../{CWE-079 => Injection/ReflectedXss}/ReflectedXss.expected | 0 .../{CWE-079 => Injection/ReflectedXss}/ReflectedXss.qlref | 0 .../{CWE-079 => Injection/ReflectedXss}/reflected_xss.py | 0 .../{CWE-089 => Injection/SqlInjection}/SqlInjection.expected | 0 .../{CWE-089 => Injection/SqlInjection}/SqlInjection.qlref | 0 .../{CWE-089 => Injection/SqlInjection}/sql_injection.py | 0 .../TarSlip/PathInjection}/PathInjection.expected | 0 .../TarSlip/PathInjection}/PathInjection.qlref | 0 .../TarSlip/PathInjection}/path_injection.py | 0 .../TarSlip/PathInjection}/test.py | 0 .../TarSlip/PathInjection}/test_chaining.py | 0 .../{CWE-022-TarSlip => Injection/TarSlip}/TarSlip.expected | 0 .../{CWE-022-TarSlip => Injection/TarSlip}/TarSlip.qlref | 0 python/ql/test/query-tests/Security/Injection/TarSlip/options | 1 + .../Security/{CWE-022-TarSlip => Injection/TarSlip}/tarslip.py | 0 .../UnsafeDeserialization}/UnsafeDeserialization.expected | 0 .../UnsafeDeserialization}/UnsafeDeserialization.qlref | 0 .../UnsafeDeserialization}/unsafe_deserialization.py | 0 114 files changed, 12 insertions(+), 10 deletions(-) rename python/ql/test/query-tests/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.expected (100%) rename python/ql/test/query-tests/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.qlref (100%) rename python/ql/test/query-tests/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/UntrustedDataToExternalAPI.expected (100%) rename python/ql/test/query-tests/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/UntrustedDataToExternalAPI.qlref (100%) rename python/ql/test/query-tests/{Security/CWE-020-ExternalAPIs => POI/ExternalAPIs}/test.py (100%) rename python/ql/test/query-tests/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/BindToAllInterfaces.expected (100%) rename python/ql/test/query-tests/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/BindToAllInterfaces.qlref (100%) rename python/ql/test/query-tests/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/BindToAllInterfaces_test.py (100%) rename python/ql/test/query-tests/Security/{CVE-2018-1281 => BadPractice/BindToAllInterfaces}/options (100%) rename python/ql/test/query-tests/Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.expected (100%) rename python/ql/test/query-tests/Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/FlaskDebug.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options rename python/ql/test/query-tests/Security/{CWE-215 => BadPractice/FlaskRunWithDebug}/test.py (100%) rename python/ql/test/query-tests/Security/{CWE-295 => BadPractice/HTTPSRequestWithoutCertValidation}/RequestWithoutValidation.expected (100%) rename python/ql/test/query-tests/Security/{CWE-295 => BadPractice/HTTPSRequestWithoutCertValidation}/RequestWithoutValidation.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-295 => BadPractice/HTTPSRequestWithoutCertValidation}/make_request.py (100%) create mode 100644 python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options rename python/ql/test/query-tests/Security/{CWE-798 => BadPractice/HardcodedCredentials}/HardcodedCredentials.expected (100%) rename python/ql/test/query-tests/Security/{CWE-798 => BadPractice/HardcodedCredentials}/HardcodedCredentials.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-798 => BadPractice/HardcodedCredentials}/test.py (100%) rename python/ql/test/query-tests/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteHostnameRegExp.expected (100%) rename python/ql/test/query-tests/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteHostnameRegExp.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteUrlSubstringSanitization.expected (100%) rename python/ql/test/query-tests/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/IncompleteUrlSubstringSanitization.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/hosttest.py (100%) rename python/ql/test/query-tests/Security/{CWE-020 => BadPractice/IncompleteUrlSanitizer}/urltest.py (100%) rename python/ql/test/query-tests/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/InsecureTemporaryFile.expected (100%) rename python/ql/test/query-tests/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/InsecureTemporaryFile.py (100%) rename python/ql/test/query-tests/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/InsecureTemporaryFile.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-377 => BadPractice/InsecureTemporaryFile}/SecureTemporaryFile.py (100%) create mode 100644 python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options rename python/ql/test/query-tests/Security/{CWE-079 => BadPractice/Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.expected (100%) rename python/ql/test/query-tests/Security/{CWE-079 => BadPractice/Jinja2RenderWithoutEscape}/Jinja2WithoutEscaping.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-079 => BadPractice/Jinja2RenderWithoutEscape}/jinja2_escaping.py (100%) rename python/ql/test/query-tests/Security/{CWE-022-TarSlip => BadPractice/Jinja2RenderWithoutEscape}/options (100%) rename python/ql/test/query-tests/Security/{CWE-295 => BadPractice/SSHMissingHostKeyValidation}/MissingHostKeyValidation.expected (100%) rename python/ql/test/query-tests/Security/{CWE-295 => BadPractice/SSHMissingHostKeyValidation}/MissingHostKeyValidation.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options rename python/ql/test/query-tests/Security/{CWE-295 => BadPractice/SSHMissingHostKeyValidation}/paramiko_host_key.py (100%) rename python/ql/test/query-tests/Security/{CWE-732 => BadPractice/WeakFilePermissions}/WeakFilePermissions.expected (100%) rename python/ql/test/query-tests/Security/{CWE-732 => BadPractice/WeakFilePermissions}/WeakFilePermissions.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options rename python/ql/test/query-tests/Security/{CWE-732 => BadPractice/WeakFilePermissions}/test.py (100%) delete mode 100644 python/ql/test/query-tests/Security/CWE-079/options delete mode 100644 python/ql/test/query-tests/Security/CWE-209/options delete mode 100644 python/ql/test/query-tests/Security/CWE-215/options delete mode 100644 python/ql/test/query-tests/Security/CWE-295/options delete mode 100644 python/ql/test/query-tests/Security/CWE-312/options delete mode 100644 python/ql/test/query-tests/Security/CWE-326/options delete mode 100644 python/ql/test/query-tests/Security/CWE-327/options delete mode 100644 python/ql/test/query-tests/Security/CWE-377/options delete mode 100644 python/ql/test/query-tests/Security/CWE-601/options delete mode 100644 python/ql/test/query-tests/Security/CWE-732/options rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.expected (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/TLS}/InsecureDefaultProtocol.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.expected (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.py (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/TLS}/InsecureProtocol.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/Crypto/TLS/options rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/BrokenCryptoAlgorithm.expected (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/BrokenCryptoAlgorithm.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/TestNode.expected (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/TestNode.ql (100%) create mode 100644 python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/test_cryptography.py (100%) rename python/ql/test/query-tests/Security/{CWE-327 => Crypto/WeakCryptoAlgorithm}/test_pycrypto.py (100%) rename python/ql/test/query-tests/Security/{CWE-326 => Crypto/WeakCryptoKey}/WeakCrypto.expected (100%) rename python/ql/test/query-tests/Security/{CWE-326 => Crypto/WeakCryptoKey}/WeakCrypto.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options rename python/ql/test/query-tests/Security/{CWE-326 => Crypto/WeakCryptoKey}/weak_crypto.py (100%) rename python/ql/test/query-tests/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextLogging.expected (100%) rename python/ql/test/query-tests/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextLogging.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextStorage.expected (100%) rename python/ql/test/query-tests/Security/{CWE-312 => Exposure/SensitiveDataExposure}/CleartextStorage.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options rename python/ql/test/query-tests/Security/{CWE-312 => Exposure/SensitiveDataExposure}/password_in_cookie.py (100%) rename python/ql/test/query-tests/Security/{CWE-312 => Exposure/SensitiveDataExposure}/test.py (100%) rename python/ql/test/query-tests/Security/{CWE-209 => Exposure/StackTraceExposure}/StackTraceExposure.expected (100%) rename python/ql/test/query-tests/Security/{CWE-209 => Exposure/StackTraceExposure}/StackTraceExposure.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options rename python/ql/test/query-tests/Security/{CWE-209 => Exposure/StackTraceExposure}/test.py (100%) rename python/ql/test/query-tests/Security/{CWE-094 => Injection/CodeInjection}/CodeInjection.expected (100%) rename python/ql/test/query-tests/Security/{CWE-094 => Injection/CodeInjection}/CodeInjection.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-094 => Injection/CodeInjection}/code_injection.py (100%) rename python/ql/test/query-tests/Security/{CWE-078-py2 => Injection/CommandInjection-py2}/CommandInjection.expected (100%) rename python/ql/test/query-tests/Security/{CWE-078-py2 => Injection/CommandInjection-py2}/CommandInjection.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-078-py2 => Injection/CommandInjection-py2}/command_injection.py (100%) rename python/ql/test/query-tests/Security/{CWE-078-py2 => Injection/CommandInjection-py2}/options (100%) rename python/ql/test/query-tests/Security/{CWE-078 => Injection/CommandInjection}/CommandInjection.expected (100%) rename python/ql/test/query-tests/Security/{CWE-078 => Injection/CommandInjection}/CommandInjection.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-078 => Injection/CommandInjection}/command_injection.py (100%) rename python/ql/test/query-tests/Security/{CWE-078 => Injection/CommandInjection}/options (100%) rename python/ql/test/query-tests/Security/{CWE-601 => Injection/OpenRedirect}/UrlRedirect.expected (100%) rename python/ql/test/query-tests/Security/{CWE-601 => Injection/OpenRedirect}/UrlRedirect.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/Injection/OpenRedirect/options rename python/ql/test/query-tests/Security/{CWE-601 => Injection/OpenRedirect}/test.py (100%) rename python/ql/test/query-tests/Security/{CWE-079 => Injection/ReflectedXss}/ReflectedXss.expected (100%) rename python/ql/test/query-tests/Security/{CWE-079 => Injection/ReflectedXss}/ReflectedXss.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-079 => Injection/ReflectedXss}/reflected_xss.py (100%) rename python/ql/test/query-tests/Security/{CWE-089 => Injection/SqlInjection}/SqlInjection.expected (100%) rename python/ql/test/query-tests/Security/{CWE-089 => Injection/SqlInjection}/SqlInjection.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-089 => Injection/SqlInjection}/sql_injection.py (100%) rename python/ql/test/query-tests/Security/{CWE-022-PathInjection => Injection/TarSlip/PathInjection}/PathInjection.expected (100%) rename python/ql/test/query-tests/Security/{CWE-022-PathInjection => Injection/TarSlip/PathInjection}/PathInjection.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-022-PathInjection => Injection/TarSlip/PathInjection}/path_injection.py (100%) rename python/ql/test/query-tests/Security/{CWE-022-PathInjection => Injection/TarSlip/PathInjection}/test.py (100%) rename python/ql/test/query-tests/Security/{CWE-022-PathInjection => Injection/TarSlip/PathInjection}/test_chaining.py (100%) rename python/ql/test/query-tests/Security/{CWE-022-TarSlip => Injection/TarSlip}/TarSlip.expected (100%) rename python/ql/test/query-tests/Security/{CWE-022-TarSlip => Injection/TarSlip}/TarSlip.qlref (100%) create mode 100644 python/ql/test/query-tests/Security/Injection/TarSlip/options rename python/ql/test/query-tests/Security/{CWE-022-TarSlip => Injection/TarSlip}/tarslip.py (100%) rename python/ql/test/query-tests/Security/{CWE-502 => Injection/UnsafeDeserialization}/UnsafeDeserialization.expected (100%) rename python/ql/test/query-tests/Security/{CWE-502 => Injection/UnsafeDeserialization}/UnsafeDeserialization.qlref (100%) rename python/ql/test/query-tests/Security/{CWE-502 => Injection/UnsafeDeserialization}/unsafe_deserialization.py (100%) diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected rename to python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref b/python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref rename to python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected rename to python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.expected diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref rename to python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py b/python/ql/test/query-tests/POI/ExternalAPIs/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py rename to python/ql/test/query-tests/POI/ExternalAPIs/test.py diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.expected similarity index 100% rename from python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected rename to python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.expected diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref rename to python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces_test.py similarity index 100% rename from python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py rename to python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces_test.py diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/options b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/options similarity index 100% rename from python/ql/test/query-tests/Security/CVE-2018-1281/options rename to python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/options diff --git a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.expected b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-215/FlaskDebug.expected rename to python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.expected diff --git a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref rename to python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref diff --git a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options new file mode 100644 index 00000000000..e552c11e561 --- /dev/null +++ b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -p ../../lib diff --git a/python/ql/test/query-tests/Security/CWE-215/test.py b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-215/test.py rename to python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/test.py diff --git a/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.expected b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.expected rename to python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.expected diff --git a/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref rename to python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.qlref diff --git a/python/ql/test/query-tests/Security/CWE-295/make_request.py b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/make_request.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-295/make_request.py rename to python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/make_request.py diff --git a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected b/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected rename to python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.expected diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref rename to python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref diff --git a/python/ql/test/query-tests/Security/CWE-798/test.py b/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-798/test.py rename to python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/test.py diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected rename to python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.expected diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref rename to python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.expected b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.expected rename to python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.expected diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref rename to python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref diff --git a/python/ql/test/query-tests/Security/CWE-020/hosttest.py b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/hosttest.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020/hosttest.py rename to python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/hosttest.py diff --git a/python/ql/test/query-tests/Security/CWE-020/urltest.py b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/urltest.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-020/urltest.py rename to python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/urltest.py diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected rename to python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.expected diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.py b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.py rename to python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref rename to python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qlref diff --git a/python/ql/test/query-tests/Security/CWE-377/SecureTemporaryFile.py b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-377/SecureTemporaryFile.py rename to python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py diff --git a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected b/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected rename to python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.expected diff --git a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref b/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref rename to python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref diff --git a/python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py b/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/jinja2_escaping.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py rename to python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/jinja2_escaping.py diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/options b/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/options similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-TarSlip/options rename to python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/options diff --git a/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.expected b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.expected rename to python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.expected diff --git a/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref rename to python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref diff --git a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-295/paramiko_host_key.py b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/paramiko_host_key.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-295/paramiko_host_key.py rename to python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/paramiko_host_key.py diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected rename to python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.expected diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref rename to python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qlref diff --git a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options new file mode 100644 index 00000000000..e552c11e561 --- /dev/null +++ b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -p ../../lib diff --git a/python/ql/test/query-tests/Security/CWE-732/test.py b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-732/test.py rename to python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/test.py diff --git a/python/ql/test/query-tests/Security/CWE-079/options b/python/ql/test/query-tests/Security/CWE-079/options deleted file mode 100644 index 492768b3481..00000000000 --- a/python/ql/test/query-tests/Security/CWE-079/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-209/options b/python/ql/test/query-tests/Security/CWE-209/options deleted file mode 100644 index 2729d5a143a..00000000000 --- a/python/ql/test/query-tests/Security/CWE-209/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=2 diff --git a/python/ql/test/query-tests/Security/CWE-215/options b/python/ql/test/query-tests/Security/CWE-215/options deleted file mode 100644 index 84717fe64cf..00000000000 --- a/python/ql/test/query-tests/Security/CWE-215/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/CWE-295/options b/python/ql/test/query-tests/Security/CWE-295/options deleted file mode 100644 index 492768b3481..00000000000 --- a/python/ql/test/query-tests/Security/CWE-295/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-312/options b/python/ql/test/query-tests/Security/CWE-312/options deleted file mode 100644 index 492768b3481..00000000000 --- a/python/ql/test/query-tests/Security/CWE-312/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-326/options b/python/ql/test/query-tests/Security/CWE-326/options deleted file mode 100644 index 492768b3481..00000000000 --- a/python/ql/test/query-tests/Security/CWE-326/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-327/options b/python/ql/test/query-tests/Security/CWE-327/options deleted file mode 100644 index 492768b3481..00000000000 --- a/python/ql/test/query-tests/Security/CWE-327/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-377/options b/python/ql/test/query-tests/Security/CWE-377/options deleted file mode 100644 index 492768b3481..00000000000 --- a/python/ql/test/query-tests/Security/CWE-377/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-601/options b/python/ql/test/query-tests/Security/CWE-601/options deleted file mode 100644 index 28b616e5f19..00000000000 --- a/python/ql/test/query-tests/Security/CWE-601/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/CWE-732/options b/python/ql/test/query-tests/Security/CWE-732/options deleted file mode 100644 index 84717fe64cf..00000000000 --- a/python/ql/test/query-tests/Security/CWE-732/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.expected b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.expected rename to python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.expected diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref rename to python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.qlref diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.expected b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.expected rename to python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.expected diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.py b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.py rename to python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.py diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref rename to python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/options b/python/ql/test/query-tests/Security/Crypto/TLS/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/Crypto/TLS/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.expected diff --git a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref diff --git a/python/ql/test/query-tests/Security/CWE-327/TestNode.expected b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/TestNode.expected rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.expected diff --git a/python/ql/test/query-tests/Security/CWE-327/TestNode.ql b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.ql similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/TestNode.ql rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.ql diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-327/test_cryptography.py b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_cryptography.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/test_cryptography.py rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_cryptography.py diff --git a/python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_pycrypto.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_pycrypto.py diff --git a/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.expected b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-326/WeakCrypto.expected rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.expected diff --git a/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-326/weak_crypto.py b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/weak_crypto.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-326/weak_crypto.py rename to python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/weak_crypto.py diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected rename to python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.expected diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref rename to python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected rename to python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.expected diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref rename to python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-312/password_in_cookie.py b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/password_in_cookie.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-312/password_in_cookie.py rename to python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/password_in_cookie.py diff --git a/python/ql/test/query-tests/Security/CWE-312/test.py b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-312/test.py rename to python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/test.py diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected rename to python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.expected diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref rename to python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.qlref diff --git a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options new file mode 100644 index 00000000000..59cbd921362 --- /dev/null +++ b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=2 diff --git a/python/ql/test/query-tests/Security/CWE-209/test.py b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-209/test.py rename to python/ql/test/query-tests/Security/Exposure/StackTraceExposure/test.py diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected b/python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected rename to python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref b/python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref rename to python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.qlref diff --git a/python/ql/test/query-tests/Security/CWE-094/code_injection.py b/python/ql/test/query-tests/Security/Injection/CodeInjection/code_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-094/code_injection.py rename to python/ql/test/query-tests/Security/Injection/CodeInjection/code_injection.py diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.expected b/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.expected rename to python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref b/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref rename to python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.qlref diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/command_injection.py b/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/command_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078-py2/command_injection.py rename to python/ql/test/query-tests/Security/Injection/CommandInjection-py2/command_injection.py diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/options b/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/options similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078-py2/options rename to python/ql/test/query-tests/Security/Injection/CommandInjection-py2/options diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected rename to python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref rename to python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.qlref diff --git a/python/ql/test/query-tests/Security/CWE-078/command_injection.py b/python/ql/test/query-tests/Security/Injection/CommandInjection/command_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078/command_injection.py rename to python/ql/test/query-tests/Security/Injection/CommandInjection/command_injection.py diff --git a/python/ql/test/query-tests/Security/CWE-078/options b/python/ql/test/query-tests/Security/Injection/CommandInjection/options similarity index 100% rename from python/ql/test/query-tests/Security/CWE-078/options rename to python/ql/test/query-tests/Security/Injection/CommandInjection/options diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected b/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected rename to python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.expected diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref b/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref rename to python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref diff --git a/python/ql/test/query-tests/Security/Injection/OpenRedirect/options b/python/ql/test/query-tests/Security/Injection/OpenRedirect/options new file mode 100644 index 00000000000..2c9a5f0a13c --- /dev/null +++ b/python/ql/test/query-tests/Security/Injection/OpenRedirect/options @@ -0,0 +1 @@ +semmle-extractor-options: --lang=3 --max-import-depth=2 -p ../../lib diff --git a/python/ql/test/query-tests/Security/CWE-601/test.py b/python/ql/test/query-tests/Security/Injection/OpenRedirect/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-601/test.py rename to python/ql/test/query-tests/Security/Injection/OpenRedirect/test.py diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected b/python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected rename to python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.expected diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref b/python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref rename to python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.qlref diff --git a/python/ql/test/query-tests/Security/CWE-079/reflected_xss.py b/python/ql/test/query-tests/Security/Injection/ReflectedXss/reflected_xss.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-079/reflected_xss.py rename to python/ql/test/query-tests/Security/Injection/ReflectedXss/reflected_xss.py diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected rename to python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref rename to python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.qlref diff --git a/python/ql/test/query-tests/Security/CWE-089/sql_injection.py b/python/ql/test/query-tests/Security/Injection/SqlInjection/sql_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-089/sql_injection.py rename to python/ql/test/query-tests/Security/Injection/SqlInjection/sql_injection.py diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected b/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected rename to python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref b/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref rename to python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.qlref diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py b/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/path_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py rename to python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/path_injection.py diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py b/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py rename to python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test.py diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py b/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test_chaining.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py rename to python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test_chaining.py diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected b/python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected rename to python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.expected diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref b/python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref rename to python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.qlref diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/options b/python/ql/test/query-tests/Security/Injection/TarSlip/options new file mode 100644 index 00000000000..b7721e6c509 --- /dev/null +++ b/python/ql/test/query-tests/Security/Injection/TarSlip/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py b/python/ql/test/query-tests/Security/Injection/TarSlip/tarslip.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py rename to python/ql/test/query-tests/Security/Injection/TarSlip/tarslip.py diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected b/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.expected similarity index 100% rename from python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected rename to python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.expected diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qlref similarity index 100% rename from python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref rename to python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qlref diff --git a/python/ql/test/query-tests/Security/CWE-502/unsafe_deserialization.py b/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/unsafe_deserialization.py similarity index 100% rename from python/ql/test/query-tests/Security/CWE-502/unsafe_deserialization.py rename to python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/unsafe_deserialization.py From 4b9e37f62d4ff31b6a4f99eedcd8ca5ce93f7668 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Feb 2021 14:37:11 +0100 Subject: [PATCH 399/429] Docs: Update list of support frameworks in Python So it follows what is we actually support with https://github.com/github/codeql/blob/6eafa9d3968a9f4752ef07e7d5159699591079c3/python/ql/src/semmle/python/Frameworks.qll --- docs/codeql/support/reusables/frameworks.rst | 23 ++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/codeql/support/reusables/frameworks.rst b/docs/codeql/support/reusables/frameworks.rst index 4427407fe9d..c04e717e295 100644 --- a/docs/codeql/support/reusables/frameworks.rst +++ b/docs/codeql/support/reusables/frameworks.rst @@ -122,19 +122,20 @@ JavaScript and TypeScript built-in support Python built-in support ==================================== -.. csv-table:: +.. csv-table:: :header-rows: 1 :class: fullWidthTable :widths: auto Name, Category - Bottle, Web framework - CherryPy, Web framework - Django, Web application framework - Falcon, Web API framework - Flask, Microframework - Pyramid, Web application framework - Tornado, Web application framework and asynchronous networking library - Turbogears, Web framework - Twisted, Networking engine - WebOb, WSGI request library + Django, Web framework + Flask, Web framework + Tornado, Web framework + PyYAML, Serialization + dill, Serialization + fabric, Utility library + invoke, Utility library + mysql-connector-python, Database + MySQLdb, Database + psycopg2, Database + sqlite3, Database From b7ea469e2652acac8074fe162260da14ade32ac9 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 3 Feb 2021 11:10:07 +0100 Subject: [PATCH 400/429] Python: Add tests for flask blueprints --- .../frameworks/flask/external_blueprint.py | 7 +++++ .../frameworks/flask/routing_test.py | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py b/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py new file mode 100644 index 00000000000..4c43b627eb2 --- /dev/null +++ b/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py @@ -0,0 +1,7 @@ +import flask + +bp3 = flask.Blueprint("bp3", __name__) + +@bp3.route("/bp3/example") # $ MISSING: routeSetup="/bp3/example" +def bp3_example(): # $ MISSING: requestHandler + return "bp 3 example" diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py index 813e3751152..3475e27455f 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py @@ -93,5 +93,32 @@ class WithoutKnownRoute2(MethodView): pass +# Blueprints +# +# see https://flask.palletsprojects.com/en/1.1.x/blueprints/ + +bp1 = flask.Blueprint("bp1", __name__) + +@bp1.route("/bp1/example/") # $ MISSING: routeSetup="/bp1/example/" +def bp1_example(foo): # $ MISSING: requestHandler routedParameter=foo + return "bp 1 example foo={}".format(foo) + +app.register_blueprint(bp1) # by default, URL of blueprints are not changed + + +bp2 = flask.Blueprint("bp2", __name__) + +@bp2.route("/example") # $ MISSING: routeSetup="/example" +def bp2_example(): # $ MISSING: requestHandler + return "bp 2 example" + +app.register_blueprint(bp2, url_prefix="/bp2") # but it is possible to add a url_prefix + + +from external_blueprint import bp3 +app.register_blueprint(bp3) + + if __name__ == "__main__": + print(app.url_map) app.run(debug=True) From 1e1cb874360707bc5fea0e9bfb3028e812600248 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 3 Feb 2021 11:32:40 +0100 Subject: [PATCH 401/429] Python: Model flask blueprints --- ...2021-02-03-flask-add-blueprint-modeling.md | 2 + .../ql/src/semmle/python/frameworks/Flask.qll | 40 +++++++++++++++++-- .../frameworks/flask/external_blueprint.py | 6 +-- .../frameworks/flask/routing_test.py | 12 +++--- 4 files changed, 47 insertions(+), 13 deletions(-) create mode 100644 python/change-notes/2021-02-03-flask-add-blueprint-modeling.md diff --git a/python/change-notes/2021-02-03-flask-add-blueprint-modeling.md b/python/change-notes/2021-02-03-flask-add-blueprint-modeling.md new file mode 100644 index 00000000000..62776a7adb4 --- /dev/null +++ b/python/change-notes/2021-02-03-flask-add-blueprint-modeling.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added modeling of flask blueprints (`flask.Blueprint`), specifically request handlers defined with such blueprints. This can result in new sources of remote user input (`RemoteFlowSource`) -- since we're now able to detect routed parameters -- and new XSS sinks from the responses of these request handlers. diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index fe394c6c8ac..30afff25922 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -72,6 +72,30 @@ private module FlaskModel { API::Node response_class() { result = [classRef(), instance()].getMember("response_class") } } + /** + * Provides models for the `flask.Blueprint` class + * + * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Blueprint. + */ + module Blueprint { + /** Gets a reference to the `flask.Blueprint` class. */ + API::Node classRef() { result = flask().getMember("Blueprint") } + + /** Gets a reference to an instance of `flask.Blueprint`. */ + API::Node instance() { result = classRef().getReturn() } + + /** + * Gets a reference to the attribute `attr_name` of an instance of `flask.Blueprint`. + */ + private API::Node instance_attr(string attr_name) { result = instance().getMember(attr_name) } + + /** Gets a reference to the `route` method on an instance of `flask.Blueprint`. */ + API::Node route() { result = instance_attr("route") } + + /** Gets a reference to the `add_url_rule` method on an instance of `flask.Blueprint`. */ + API::Node add_url_rule() { result = instance_attr("add_url_rule") } + } + // ------------------------------------------------------------------------- // flask.views // ------------------------------------------------------------------------- @@ -222,12 +246,16 @@ private module FlaskModel { } /** - * A call to the `route` method on an instance of `flask.Flask`. + * A call to the `route` method on an instance of `flask.Flask` or an instance of `flask.Blueprint`. * * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.route */ private class FlaskAppRouteCall extends FlaskRouteSetup, DataFlow::CallCfgNode { - FlaskAppRouteCall() { this.getFunction() = flask::Flask::route().getAUse() } + FlaskAppRouteCall() { + this.getFunction() = flask::Flask::route().getAUse() + or + this.getFunction() = flask::Blueprint::route().getAUse() + } override DataFlow::Node getUrlPatternArg() { result in [this.getArg(0), this.getArgByName("rule")] @@ -237,12 +265,16 @@ private module FlaskModel { } /** - * A call to the `add_url_rule` method on an instance of `flask.Flask`. + * A call to the `add_url_rule` method on an instance of `flask.Flask` or an instance of `flask.Blueprint`. * * See https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.add_url_rule */ private class FlaskAppAddUrlRuleCall extends FlaskRouteSetup, DataFlow::CallCfgNode { - FlaskAppAddUrlRuleCall() { this.getFunction() = flask::Flask::add_url_rule().getAUse() } + FlaskAppAddUrlRuleCall() { + this.getFunction() = flask::Flask::add_url_rule().getAUse() + or + this.getFunction() = flask::Blueprint::add_url_rule().getAUse() + } override DataFlow::Node getUrlPatternArg() { result in [this.getArg(0), this.getArgByName("rule")] diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py b/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py index 4c43b627eb2..d426cb37867 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/external_blueprint.py @@ -2,6 +2,6 @@ import flask bp3 = flask.Blueprint("bp3", __name__) -@bp3.route("/bp3/example") # $ MISSING: routeSetup="/bp3/example" -def bp3_example(): # $ MISSING: requestHandler - return "bp 3 example" +@bp3.route("/bp3/example") # $ routeSetup="/bp3/example" +def bp3_example(): # $ requestHandler + return "bp 3 example" # $ HttpResponse diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py index 3475e27455f..1bbff4fed37 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py @@ -99,18 +99,18 @@ class WithoutKnownRoute2(MethodView): bp1 = flask.Blueprint("bp1", __name__) -@bp1.route("/bp1/example/") # $ MISSING: routeSetup="/bp1/example/" -def bp1_example(foo): # $ MISSING: requestHandler routedParameter=foo - return "bp 1 example foo={}".format(foo) +@bp1.route("/bp1/example/") # $ routeSetup="/bp1/example/" +def bp1_example(foo): # $ requestHandler routedParameter=foo + return "bp 1 example foo={}".format(foo) # $ HttpResponse app.register_blueprint(bp1) # by default, URL of blueprints are not changed bp2 = flask.Blueprint("bp2", __name__) -@bp2.route("/example") # $ MISSING: routeSetup="/example" -def bp2_example(): # $ MISSING: requestHandler - return "bp 2 example" +@bp2.route("/example") # $ routeSetup="/example" +def bp2_example(): # $ requestHandler + return "bp 2 example" # $ HttpResponse app.register_blueprint(bp2, url_prefix="/bp2") # but it is possible to add a url_prefix From bc8e61366b7f3dc4f16d2eafefdec8a04e3bcbe5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Feb 2021 15:29:25 +0100 Subject: [PATCH 402/429] Python: Clarify comment about flask blueprint URL prefixes --- .../library-tests/frameworks/flask/routing_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py index 1bbff4fed37..11e44f52e71 100644 --- a/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/flask/routing_test.py @@ -103,7 +103,7 @@ bp1 = flask.Blueprint("bp1", __name__) def bp1_example(foo): # $ requestHandler routedParameter=foo return "bp 1 example foo={}".format(foo) # $ HttpResponse -app.register_blueprint(bp1) # by default, URL of blueprints are not changed +app.register_blueprint(bp1) # by default, URLs of blueprints are not prefixed bp2 = flask.Blueprint("bp2", __name__) @@ -112,7 +112,7 @@ bp2 = flask.Blueprint("bp2", __name__) def bp2_example(): # $ requestHandler return "bp 2 example" # $ HttpResponse -app.register_blueprint(bp2, url_prefix="/bp2") # but it is possible to add a url_prefix +app.register_blueprint(bp2, url_prefix="/bp2") # but it is possible to add a URL prefix from external_blueprint import bp3 From bf03c0f419253fff4056ecc826e200f82a3368f8 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 11 Feb 2021 17:49:43 +0000 Subject: [PATCH 403/429] Port InlineExpectationsTest for the Java analysis --- config/identical-files.json | 1 + .../TestUtilities/InlineExpectationsTest.qll | 343 ++++++++++++++++++ .../InlineExpectationsTestPrivate.qll | 12 + 3 files changed, 356 insertions(+) create mode 100644 java/ql/test/TestUtilities/InlineExpectationsTest.qll create mode 100644 java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll diff --git a/config/identical-files.json b/config/identical-files.json index 5a8efc3405a..d68dabba861 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -356,6 +356,7 @@ ], "Inline Test Expectations": [ "cpp/ql/test/TestUtilities/InlineExpectationsTest.qll", + "java/ql/test/TestUtilities/InlineExpectationsTest.qll", "python/ql/test/TestUtilities/InlineExpectationsTest.qll" ], "C++ ExternalAPIs": [ diff --git a/java/ql/test/TestUtilities/InlineExpectationsTest.qll b/java/ql/test/TestUtilities/InlineExpectationsTest.qll new file mode 100644 index 00000000000..35798415078 --- /dev/null +++ b/java/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -0,0 +1,343 @@ +/** + * Provides a library for writing QL tests whose success or failure is based on expected results + * embedded in the test source code as comments, rather than a `.expected` file. + * + * To add this framework to a new language: + * - Add a file `InlineExpectationsTestPrivate.qll` that defines a `LineComment` class. This class + * must support a `getContents` method that returns the contents of the given comment, _excluding_ + * the comment indicator itself. It should also define `toString` and `getLocation` as usual. + * + * To create a new inline expectations test: + * - Declare a class that extends `InlineExpectationsTest`. In the characteristic predicate of the + * new class, bind `this` to a unique string (usually the name of the test). + * - Override the `hasActualResult()` predicate to produce the actual results of the query. For each + * result, specify a `Location`, a text description of the element for which the result was + * reported, a short string to serve as the tag to identify expected results for this test, and the + * expected value of the result. + * - Override `getARelevantTag()` to return the set of tags that can be produced by + * `hasActualResult()`. Often this is just a single tag. + * + * Example: + * ```ql + * class ConstantValueTest extends InlineExpectationsTest { + * ConstantValueTest() { this = "ConstantValueTest" } + * + * override string getARelevantTag() { + * // We only use one tag for this test. + * result = "const" + * } + * + * override predicate hasActualResult( + * Location location, string element, string tag, string value + * ) { + * exists(Expr e | + * tag = "const" and // The tag for this test. + * value = e.getValue() and // The expected value. Will only hold for constant expressions. + * location = e.getLocation() and // The location of the result to be reported. + * element = e.toString() // The display text for the result. + * ) + * } + * } + * ``` + * + * There is no need to write a `select` clause or query predicate. All of the differences between + * expected results and actual results will be reported in the `failures()` query predicate. + * + * To annotate the test source code with an expected result, place a comment starting with a `$` on the + * same line as the expected result, with text of the following format as the body of the comment: + * + * `tag=expected-value` + * + * Where `tag` is the value of the `tag` parameter from `hasActualResult()`, and `expected-value` is + * the value of the `value` parameter from `hasActualResult()`. The `=expected-value` portion may be + * omitted, in which case `expected-value` is treated as the empty string. Multiple expectations may + * be placed in the same comment. Any actual result that + * appears on a line that does not contain a matching expected result comment will be reported with + * a message of the form "Unexpected result: tag=value". Any expected result comment for which there + * is no matching actual result will be reported with a message of the form + * "Missing result: tag=expected-value". + * + * Example: + * ```cpp + * int i = x + 5; // $const=5 + * int j = y + (7 - 3) // $const=7 const=3 const=4 // The result of the subtraction is a constant. + * ``` + * + * For tests that contain known missing and spurious results, it is possible to further + * annotate that a particular expected result is known to be spurious, or that a particular + * missing result is known to be missing: + * + * `$ SPURIOUS: tag=expected-value` // Spurious result + * `$ MISSING: tag=expected-value` // Missing result + * + * A spurious expectation is treated as any other expected result, except that if there is no + * matching actual result, the message will be of the form "Fixed spurious result: tag=value". A + * missing expectation is treated as if there were no expected result, except that if a + * matching expected result is found, the message will be of the form + * "Fixed missing result: tag=value". + * + * A single line can contain all the expected, spurious and missing results of that line. For instance: + * `$ tag1=value1 SPURIOUS: tag2=value2 MISSING: tag3=value3`. + * + * If the same result value is expected for two or more tags on the same line, there is a shorthand + * notation available: + * + * `tag1,tag2=expected-value` + * + * is equivalent to: + * + * `tag1=expected-value tag2=expected-value` + */ + +private import InlineExpectationsTestPrivate + +/** + * Base class for tests with inline expectations. The test extends this class to provide the actual + * results of the query, which are then compared with the expected results in comments to produce a + * list of failure messages that point out where the actual results differ from the expected + * results. + */ +abstract class InlineExpectationsTest extends string { + bindingset[this] + InlineExpectationsTest() { any() } + + /** + * Returns all tags that can be generated by this test. Most tests will only ever produce a single + * tag. Any expected result comments for a tag that is not returned by the `getARelevantTag()` + * predicate for an active test will be ignored. This makes it possible to write multiple tests in + * different `.ql` files that all query the same source code. + */ + abstract string getARelevantTag(); + + /** + * Returns the actual results of the query that is being tested. Each result consist of the + * following values: + * - `location` - The source code location of the result. Any expected result comment must appear + * on the start line of this location. + * - `element` - Display text for the element on which the result is reported. + * - `tag` - The tag that marks this result as coming from this test. This must be one of the tags + * returned by `getARelevantTag()`. + * - `value` - The value of the result, which will be matched against the value associated with + * `tag` in any expected result comment on that line. + */ + abstract predicate hasActualResult(Location location, string element, string tag, string value); + + final predicate hasFailureMessage(FailureLocatable element, string message) { + exists(ActualResult actualResult | + actualResult.getTest() = this and + element = actualResult and + ( + exists(FalseNegativeExpectation falseNegative | + falseNegative.matchesActualResult(actualResult) and + message = "Fixed missing result:" + falseNegative.getExpectationText() + ) + or + not exists(ValidExpectation expectation | expectation.matchesActualResult(actualResult)) and + message = "Unexpected result: " + actualResult.getExpectationText() + ) + ) + or + exists(ValidExpectation expectation | + not exists(ActualResult actualResult | expectation.matchesActualResult(actualResult)) and + expectation.getTag() = getARelevantTag() and + element = expectation and + ( + expectation instanceof GoodExpectation and + message = "Missing result:" + expectation.getExpectationText() + or + expectation instanceof FalsePositiveExpectation and + message = "Fixed spurious result:" + expectation.getExpectationText() + ) + ) + or + exists(InvalidExpectation expectation | + element = expectation and + message = "Invalid expectation syntax: " + expectation.getExpectation() + ) + } +} + +/** + * RegEx pattern to match a comment containing one or more expected results. The comment must have + * `$` as its first non-whitespace character. Any subsequent character + * is treated as part of the expected results, except that the comment may contain a `//` sequence + * to treat the remainder of the line as a regular (non-interpreted) comment. + */ +private string expectationCommentPattern() { result = "\\s*\\$((?:[^/]|/[^/])*)(?://.*)?" } + +/** + * The possible columns in an expectation comment. The `TDefaultColumn` branch represents the first + * column in a comment. This column is not precedeeded by a name. `TNamedColumn(name)` represents a + * column containing expected results preceeded by the string `name:`. + */ +private newtype TColumn = + TDefaultColumn() or + TNamedColumn(string name) { name = ["MISSING", "SPURIOUS"] } + +bindingset[start, content] +private int getEndOfColumnPosition(int start, string content) { + result = + min(string name, int cand | + exists(TNamedColumn(name)) and + cand = content.indexOf(name + ":") and + cand > start + | + cand + ) + or + not exists(string name | + exists(TNamedColumn(name)) and + content.indexOf(name + ":") > start + ) and + result = content.length() +} + +private predicate getAnExpectation( + LineComment comment, TColumn column, string expectation, string tags, string value +) { + exists(string content | + content = comment.getContents().regexpCapture(expectationCommentPattern(), 1) and + ( + column = TDefaultColumn() and + exists(int end | + end = getEndOfColumnPosition(0, content) and + expectation = content.prefix(end).regexpFind(expectationPattern(), _, _).trim() + ) + or + exists(string name, int start, int end | + column = TNamedColumn(name) and + start = content.indexOf(name + ":") + name.length() + 1 and + end = getEndOfColumnPosition(start, content) and + expectation = content.substring(start, end).regexpFind(expectationPattern(), _, _).trim() + ) + ) + ) and + tags = expectation.regexpCapture(expectationPattern(), 1) and + if exists(expectation.regexpCapture(expectationPattern(), 2)) + then value = expectation.regexpCapture(expectationPattern(), 2) + else value = "" +} + +private string getColumnString(TColumn column) { + column = TDefaultColumn() and result = "" + or + column = TNamedColumn(result) +} + +/** + * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or + * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character + * must not be a digit), optionally followed by `=` and the expected value. + */ +private string expectationPattern() { + exists(string tag, string tags, string value | + tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and + value = "((?:\"[^\"]*\"|'[^']*'|\\S+)*)" and + result = tags + "(?:=" + value + ")?" + ) +} + +private newtype TFailureLocatable = + TActualResult( + InlineExpectationsTest test, Location location, string element, string tag, string value + ) { + test.hasActualResult(location, element, tag, value) + } or + TValidExpectation(LineComment comment, string tag, string value, string knownFailure) { + exists(TColumn column, string tags | + getAnExpectation(comment, column, _, tags, value) and + tag = tags.splitAt(",") and + knownFailure = getColumnString(column) + ) + } or + TInvalidExpectation(LineComment comment, string expectation) { + getAnExpectation(comment, _, expectation, _, _) and + not expectation.regexpMatch(expectationPattern()) + } + +class FailureLocatable extends TFailureLocatable { + string toString() { none() } + + Location getLocation() { none() } + + final string getExpectationText() { result = getTag() + "=" + getValue() } + + string getTag() { none() } + + string getValue() { none() } +} + +class ActualResult extends FailureLocatable, TActualResult { + InlineExpectationsTest test; + Location location; + string element; + string tag; + string value; + + ActualResult() { this = TActualResult(test, location, element, tag, value) } + + override string toString() { result = element } + + override Location getLocation() { result = location } + + InlineExpectationsTest getTest() { result = test } + + override string getTag() { result = tag } + + override string getValue() { result = value } +} + +abstract private class Expectation extends FailureLocatable { + LineComment comment; + + override string toString() { result = comment.toString() } + + override Location getLocation() { result = comment.getLocation() } +} + +private class ValidExpectation extends Expectation, TValidExpectation { + string tag; + string value; + string knownFailure; + + ValidExpectation() { this = TValidExpectation(comment, tag, value, knownFailure) } + + override string getTag() { result = tag } + + override string getValue() { result = value } + + string getKnownFailure() { result = knownFailure } + + predicate matchesActualResult(ActualResult actualResult) { + getLocation().getStartLine() = actualResult.getLocation().getStartLine() and + getLocation().getFile() = actualResult.getLocation().getFile() and + getTag() = actualResult.getTag() and + getValue() = actualResult.getValue() + } +} + +/* Note: These next three classes correspond to all the possible values of type `TColumn`. */ +class GoodExpectation extends ValidExpectation { + GoodExpectation() { getKnownFailure() = "" } +} + +class FalsePositiveExpectation extends ValidExpectation { + FalsePositiveExpectation() { getKnownFailure() = "SPURIOUS" } +} + +class FalseNegativeExpectation extends ValidExpectation { + FalseNegativeExpectation() { getKnownFailure() = "MISSING" } +} + +class InvalidExpectation extends Expectation, TInvalidExpectation { + string expectation; + + InvalidExpectation() { this = TInvalidExpectation(comment, expectation) } + + string getExpectation() { result = expectation } +} + +query predicate failures(FailureLocatable element, string message) { + exists(InlineExpectationsTest test | test.hasFailureMessage(element, message)) +} diff --git a/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll b/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll new file mode 100644 index 00000000000..e2c0e0091ba --- /dev/null +++ b/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll @@ -0,0 +1,12 @@ +import java + +/** + * A class representing line comments in Java, which is simply Javadoc restricted + * to EOL comments, with an extra accessor used by the InlineExpectations core code + */ +class LineComment extends Javadoc { + LineComment() { isEolComment(this) } + + /** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */ + string getContents() { result = this.getChild(0).toString() } +} From a2eeffa9c0cced684ace5ff6780e5afaaa8ed1fc Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 9 Feb 2021 14:21:39 +0000 Subject: [PATCH 404/429] Add support for Apache Commons Lang StringUtils --- .../2021-02-09-commons-string-utils.md | 2 + .../code/java/frameworks/apache/Lang.qll | 55 + .../frameworks/apache-commons-lang3/Test.java | 278 +++++ .../apache-commons-lang3/flow.expected | 0 .../frameworks/apache-commons-lang3/flow.ql | 30 + .../frameworks/apache-commons-lang3/options | 1 + .../org/apache/commons/lang3/StringUtils.java | 963 ++++++++++++++++++ 7 files changed, 1329 insertions(+) create mode 100644 java/change-notes/2021-02-09-commons-string-utils.md create mode 100644 java/ql/test/library-tests/frameworks/apache-commons-lang3/Test.java create mode 100644 java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.expected create mode 100644 java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.ql create mode 100644 java/ql/test/library-tests/frameworks/apache-commons-lang3/options create mode 100644 java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java diff --git a/java/change-notes/2021-02-09-commons-string-utils.md b/java/change-notes/2021-02-09-commons-string-utils.md new file mode 100644 index 00000000000..0e2a4037fb2 --- /dev/null +++ b/java/change-notes/2021-02-09-commons-string-utils.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added support for the Apache Commons Lang StringUtils library. diff --git a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll index 6f5c8e0d8d1..6bec45240d7 100644 --- a/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll +++ b/java/ql/src/semmle/code/java/frameworks/apache/Lang.qll @@ -63,3 +63,58 @@ private class ApacheLangArrayUtilsTaintPreservingMethod extends TaintPreservingC src = [0, 2] } } + +private Type getAnExcludedParameterType() { + result instanceof PrimitiveType or + result.(RefType).hasQualifiedName("java.nio.charset", "Charset") or + result.(RefType).hasQualifiedName("java.util", "Locale") +} + +private class ApacheStringUtilsTaintPreservingMethod extends TaintPreservingCallable { + ApacheStringUtilsTaintPreservingMethod() { + this.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "StringUtils") and + this.hasName([ + "abbreviate", "abbreviateMiddle", "appendIfMissing", "appendIfMissingIgnoreCase", + "capitalize", "center", "chomp", "chop", "defaultIfBlank", "defaultIfEmpty", + "defaultString", "deleteWhitespace", "difference", "firstNonBlank", "firstNonEmpty", + "getBytes", "getCommonPrefix", "getDigits", "getIfBlank", "getIfEmpty", "join", "joinWith", + "left", "leftPad", "lowerCase", "mid", "normalizeSpace", "overlay", "prependIfMissing", + "prependIfMissingIgnoreCase", "remove", "removeAll", "removeEnd", "removeEndIgnoreCase", + "removeFirst", "removeIgnoreCase", "removePattern", "removeStart", "removeStartIgnoreCase", + "repeat", "replace", "replaceAll", "replaceChars", "replaceEach", "replaceEachRepeatedly", + "replaceFirst", "replaceIgnoreCase", "replaceOnce", "replaceOnceIgnoreCase", + "replacePattern", "reverse", "reverseDelimited", "right", "rightPad", "rotate", "split", + "splitByCharacterType", "splitByCharacterTypeCamelCase", "splitByWholeSeparator", + "splitByWholeSeparatorPreserveAllTokens", "splitPreserveAllTokens", "strip", "stripAccents", + "stripAll", "stripEnd", "stripStart", "stripToEmpty", "stripToNull", "substring", + "substringAfter", "substringAfterLast", "substringBefore", "substringBeforeLast", + "substringBetween", "substringsBetween", "swapCase", "toCodePoints", "toEncodedString", + "toRootLowerCase", "toRootUpperCase", "toString", "trim", "trimToEmpty", "trimToNull", + "truncate", "uncapitalize", "unwrap", "upperCase", "valueOf", "wrap", "wrapIfMissing" + ]) + } + + private predicate isExcludedParameter(int arg) { + this.getName().matches(["appendIfMissing%", "prependIfMissing%"]) and arg = [2, 3] + or + this.getName().matches(["remove%", "split%", "substring%", "strip%"]) and + arg = [1 .. getNumberOfParameters() - 1] + or + this.getName().matches(["chomp", "getBytes", "replace%", "toString", "unwrap"]) and arg = 1 + or + this.getName() = "join" and + // Exclude joins of types that render numerically (char[] and non-primitive arrays + // are still considered taint sources) + exists(PrimitiveType pt | + this.getParameterType(arg).(Array).getComponentType() = pt and + not pt instanceof CharacterType + ) and + arg = 0 + } + + override predicate returnsTaintFrom(int arg) { + arg = [0 .. getNumberOfParameters() - 1] and + not this.getParameterType(arg) = getAnExcludedParameterType() and + not isExcludedParameter(arg) + } +} diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/Test.java b/java/ql/test/library-tests/frameworks/apache-commons-lang3/Test.java new file mode 100644 index 00000000000..0a554a7d449 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/Test.java @@ -0,0 +1,278 @@ +import org.apache.commons.lang3.StringUtils; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +class Test { + String taint() { return "tainted"; } + + void sink(Object o) {} + + void test() throws Exception { + + // All these calls should convey taint to `sink` except as noted. + sink(StringUtils.abbreviate(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviate(taint(), 0, 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviate(taint(), "...", 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviate("Untainted", taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviate(taint(), "...", 0, 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviate("Untainted", taint(), 0, 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviateMiddle(taint(), "...", 0)); // $hasTaintFlow=y + sink(StringUtils.abbreviateMiddle("Untainted", taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.appendIfMissing(taint(), "suffix", "candsuffix1", "candsuffix2")); // $hasTaintFlow=y + sink(StringUtils.appendIfMissing("prefix", taint(), "candsuffix1", "candsuffix2")); // $hasTaintFlow=y + // (next 2 calls) GOOD: candidate suffixes do not flow to the return value. + sink(StringUtils.appendIfMissing("prefix", "suffix", taint(), "candsuffix2")); + sink(StringUtils.appendIfMissing("prefix", "suffix", "candsuffix1", taint())); + sink(StringUtils.appendIfMissingIgnoreCase(taint(), "suffix", "candsuffix1", "candsuffix2")); // $hasTaintFlow=y + sink(StringUtils.appendIfMissingIgnoreCase("prefix", taint(), "candsuffix1", "candsuffix2")); // $hasTaintFlow=y + // (next 2 calls) GOOD: candidate suffixes do not flow to the return value. + sink(StringUtils.appendIfMissingIgnoreCase("prefix", "suffix", taint(), "candsuffix2")); + sink(StringUtils.appendIfMissingIgnoreCase("prefix", "suffix", "candsuffix1", taint())); + sink(StringUtils.capitalize(taint())); // $hasTaintFlow=y + sink(StringUtils.center(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.center(taint(), 0, 'x')); // $hasTaintFlow=y + sink(StringUtils.center(taint(), 0, "padding string")); // $hasTaintFlow=y + sink(StringUtils.center("Center me", 0, taint())); // $hasTaintFlow=y + sink(StringUtils.chomp(taint())); // $hasTaintFlow=y + sink(StringUtils.chomp(taint(), "separator")); // $hasTaintFlow=y + // GOOD: separator does not flow to the return value. + sink(StringUtils.chomp("Chomp me", taint())); + sink(StringUtils.chop(taint())); // $hasTaintFlow=y + sink(StringUtils.defaultIfBlank(taint(), "default")); // $hasTaintFlow=y + sink(StringUtils.defaultIfBlank("Perhaps blank", taint())); // $hasTaintFlow=y + sink(StringUtils.defaultIfEmpty(taint(), "default")); // $hasTaintFlow=y + sink(StringUtils.defaultIfEmpty("Perhaps empty", taint())); // $hasTaintFlow=y + sink(StringUtils.defaultString(taint())); // $hasTaintFlow=y + sink(StringUtils.defaultString(taint(), "default string")); // $hasTaintFlow=y + sink(StringUtils.defaultString("perhaps null", taint())); // $hasTaintFlow=y + sink(StringUtils.deleteWhitespace(taint())); // $hasTaintFlow=y + sink(StringUtils.difference(taint(), "rhs")); // $hasTaintFlow=y + sink(StringUtils.difference("lhs", taint())); // $hasTaintFlow=y + sink(StringUtils.firstNonBlank(taint(), "second string")); // $hasTaintFlow=y + sink(StringUtils.firstNonBlank("first string", taint())); // $hasTaintFlow=y + sink(StringUtils.firstNonEmpty(taint(), "second string")); // $hasTaintFlow=y + sink(StringUtils.firstNonEmpty("first string", taint())); // $hasTaintFlow=y + sink(StringUtils.getBytes(taint(), (Charset)null)); // $hasTaintFlow=y + sink(StringUtils.getBytes(taint(), "some charset")); // $hasTaintFlow=y + // GOOD: charset names are not a source of taint + sink(StringUtils.getBytes("some string", taint())); + sink(StringUtils.getCommonPrefix(taint(), "second string")); // $hasTaintFlow=y + sink(StringUtils.getCommonPrefix("first string", taint())); // $hasTaintFlow=y + sink(StringUtils.getDigits(taint())); // $hasTaintFlow=y + sink(StringUtils.getIfBlank(taint(), () -> "default")); // $hasTaintFlow=y + sink(StringUtils.getIfEmpty(taint(), () -> "default")); // $hasTaintFlow=y + // BAD (but not detected yet): latent taint in lambdas + sink(StringUtils.getIfBlank("maybe blank", () -> taint())); + sink(StringUtils.getIfEmpty("maybe blank", () -> taint())); + // GOOD: byte arrays render as numbers, so can't usefully convey most forms + // of tainted data. + sink(StringUtils.join(StringUtils.getBytes(taint(), "UTF-8"), ' ')); + sink(StringUtils.join(StringUtils.getBytes(taint(), "UTF-8"), ' ', 0, 0)); + sink(StringUtils.join(taint().toCharArray(), ' ')); // $hasTaintFlow=y + sink(StringUtils.join(taint().toCharArray(), ' ', 0, 0)); // $hasTaintFlow=y + // Testing the Iterable overloads of `join` + List taintedList = new ArrayList<>(); + taintedList.add(taint()); + sink(StringUtils.join(taintedList, ' ')); // $hasTaintFlow=y + sink(StringUtils.join(taintedList, "sep")); // $hasTaintFlow=y + List untaintedList = new ArrayList<>(); + sink(StringUtils.join(untaintedList, taint())); // $hasTaintFlow=y + // Testing the Iterator overloads of `join` + sink(StringUtils.join(taintedList.iterator(), ' ')); // $hasTaintFlow=y + sink(StringUtils.join(taintedList.iterator(), "sep")); // $hasTaintFlow=y + sink(StringUtils.join(untaintedList.iterator(), taint())); // $hasTaintFlow=y + // Testing the List overloads of `join`, which have start/end indices + sink(StringUtils.join(taintedList, ' ', 0, 0)); // $hasTaintFlow=y + sink(StringUtils.join(taintedList, "sep", 0, 0)); // $hasTaintFlow=y + sink(StringUtils.join(untaintedList, taint(), 0, 0)); // $hasTaintFlow=y + // Testing the Object[] overloads of `join`, which may have start/end indices + Object[] taintedArray = new Object[] { taint() }; + sink(StringUtils.join(taintedArray, ' ')); // $hasTaintFlow=y + sink(StringUtils.join(taintedArray, "sep")); // $hasTaintFlow=y + sink(StringUtils.join(taintedArray, ' ', 0, 0)); // $hasTaintFlow=y + sink(StringUtils.join(taintedArray, "sep", 0, 0)); // $hasTaintFlow=y + Object[] untaintedArray = new Object[] { "safe" }; + sink(StringUtils.join(untaintedArray, taint())); // $hasTaintFlow=y + sink(StringUtils.join(untaintedArray, taint(), 0, 0)); // $hasTaintFlow=y + // Testing the variadic overload of `join` and `joinWith` + sink(StringUtils.join(taint(), "other string")); // $hasTaintFlow=y + sink(StringUtils.join("other string before", taint())); // $hasTaintFlow=y + sink(StringUtils.joinWith("separator", taint(), "other string")); // $hasTaintFlow=y + sink(StringUtils.joinWith("separator", "other string before", taint())); // $hasTaintFlow=y + sink(StringUtils.joinWith(taint(), "other string before", "other string after")); // $hasTaintFlow=y + // End of `join` tests + sink(StringUtils.left(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.leftPad(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.leftPad(taint(), 0, ' ')); // $hasTaintFlow=y + sink(StringUtils.leftPad(taint(), 0, "padding")); // $hasTaintFlow=y + sink(StringUtils.leftPad("to pad", 0, taint())); // $hasTaintFlow=y + sink(StringUtils.lowerCase(taint())); // $hasTaintFlow=y + sink(StringUtils.lowerCase(taint(), Locale.UK)); // $hasTaintFlow=y + sink(StringUtils.mid(taint(), 0, 0)); // $hasTaintFlow=y + sink(StringUtils.normalizeSpace(taint())); // $hasTaintFlow=y + sink(StringUtils.overlay(taint(), "overlay", 0, 0)); // $hasTaintFlow=y + sink(StringUtils.overlay("underlay", taint(), 0, 0)); // $hasTaintFlow=y + sink(StringUtils.prependIfMissing(taint(), "append prefix", "check prefix 1", "check prefix 2")); // $hasTaintFlow=y + sink(StringUtils.prependIfMissing("original string", taint(), "check prefix 1", "check prefix 2")); // $hasTaintFlow=y + // (next 2 calls) GOOD: args 3+ are checked against but do not propagate to the return value + sink(StringUtils.prependIfMissing("original string", "append prefix", taint(), "check prefix 2")); + sink(StringUtils.prependIfMissing("original string", "append prefix", "check prefix 1", taint())); + sink(StringUtils.prependIfMissingIgnoreCase(taint(), "append prefix", "check prefix 1", "check prefix 2")); // $hasTaintFlow=y + sink(StringUtils.prependIfMissingIgnoreCase("original string", taint(), "check prefix 1", "check prefix 2")); // $hasTaintFlow=y + // (next 2 calls) GOOD: args 3+ are checked against but do not propagate to the return value + sink(StringUtils.prependIfMissingIgnoreCase("original string", "append prefix", taint(), "check prefix 2")); + sink(StringUtils.prependIfMissingIgnoreCase("original string", "append prefix", "check prefix 1", taint())); + sink(StringUtils.remove(taint(), ' ')); // $hasTaintFlow=y + sink(StringUtils.remove(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeAll(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeEnd(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeEndIgnoreCase(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeFirst(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeIgnoreCase(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removePattern(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeStart(taint(), "delete me")); // $hasTaintFlow=y + sink(StringUtils.removeStartIgnoreCase(taint(), "delete me")); // $hasTaintFlow=y + // GOOD (next 9 calls): the removed string doesn't propagate to the return value + sink(StringUtils.remove("remove from", taint())); + sink(StringUtils.removeAll("remove from", taint())); + sink(StringUtils.removeEnd("remove from", taint())); + sink(StringUtils.removeEndIgnoreCase("remove from", taint())); + sink(StringUtils.removeFirst("remove from", taint())); + sink(StringUtils.removeIgnoreCase("remove from", taint())); + sink(StringUtils.removePattern("remove from", taint())); + sink(StringUtils.removeStart("remove from", taint())); + sink(StringUtils.removeStartIgnoreCase("remove from", taint())); + sink(StringUtils.repeat(taint(), 1)); // $hasTaintFlow=y + sink(StringUtils.repeat(taint(), "separator", 1)); // $hasTaintFlow=y + sink(StringUtils.repeat("repeat me", taint(), 1)); // $hasTaintFlow=y + sink(StringUtils.replace(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replace("haystack", "search", taint())); // $hasTaintFlow=y + sink(StringUtils.replace(taint(), "search", "replacement", 0)); // $hasTaintFlow=y + sink(StringUtils.replace("haystack", "search", taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.replaceAll(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replaceAll("haystack", "search", taint())); // $hasTaintFlow=y + sink(StringUtils.replaceChars(taint(), 'a', 'b')); // $hasTaintFlow=y + sink(StringUtils.replaceChars(taint(), "abc", "xyz")); // $hasTaintFlow=y + sink(StringUtils.replaceChars("haystack", "abc", taint())); // $hasTaintFlow=y + sink(StringUtils.replaceEach(taint(), new String[] { "search" }, new String[] { "replacement" })); // $hasTaintFlow=y + sink(StringUtils.replaceEach("haystack", new String[] { "search" }, new String[] { taint() })); // $hasTaintFlow=y + sink(StringUtils.replaceEachRepeatedly(taint(), new String[] { "search" }, new String[] { "replacement" })); // $hasTaintFlow=y + sink(StringUtils.replaceEachRepeatedly("haystack", new String[] { "search" }, new String[] { taint() })); // $hasTaintFlow=y + sink(StringUtils.replaceFirst(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replaceFirst("haystack", "search", taint())); // $hasTaintFlow=y + sink(StringUtils.replaceIgnoreCase(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replaceIgnoreCase("haystack", "search", taint())); // $hasTaintFlow=y + sink(StringUtils.replaceOnce(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replaceOnce("haystack", "search", taint())); // $hasTaintFlow=y + sink(StringUtils.replaceOnceIgnoreCase(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replaceOnceIgnoreCase("haystack", "search", taint())); // $hasTaintFlow=y + sink(StringUtils.replacePattern(taint(), "search", "replacement")); // $hasTaintFlow=y + sink(StringUtils.replacePattern("haystack", "search", taint())); // $hasTaintFlow=y + // GOOD (next 11 calls): searched string in replace methods does not flow to the return value. + sink(StringUtils.replace("haystack", taint(), "replacement")); + sink(StringUtils.replace("haystack", taint(), "replacement", 0)); + sink(StringUtils.replaceAll("haystack", taint(), "replacement")); + sink(StringUtils.replaceChars("haystack", taint(), "xyz")); + sink(StringUtils.replaceEach("haystack", new String[] { taint() }, new String[] { "replacement" })); + sink(StringUtils.replaceEachRepeatedly("haystack", new String[] { taint() }, new String[] { "replacement" })); + sink(StringUtils.replaceFirst("haystack", taint(), "replacement")); + sink(StringUtils.replaceIgnoreCase("haystack", taint(), "replacement")); + sink(StringUtils.replaceOnce("haystack", taint(), "replacement")); + sink(StringUtils.replaceOnceIgnoreCase("haystack", taint(), "replacement")); + sink(StringUtils.replacePattern("haystack", taint(), "replacement")); + sink(StringUtils.reverse(taint())); // $hasTaintFlow=y + sink(StringUtils.reverseDelimited(taint(), ',')); // $hasTaintFlow=y + sink(StringUtils.right(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.rightPad(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.rightPad(taint(), 0, ' ')); // $hasTaintFlow=y + sink(StringUtils.rightPad(taint(), 0, "padding")); // $hasTaintFlow=y + sink(StringUtils.rightPad("to pad", 0, taint())); // $hasTaintFlow=y + sink(StringUtils.rotate(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.split(taint())); // $hasTaintFlow=y + sink(StringUtils.split(taint(), ' ')); // $hasTaintFlow=y + sink(StringUtils.split(taint(), " ,; // $hasTaintFlow=y")); // $hasTaintFlow=y + sink(StringUtils.split(taint(), " ,; // $hasTaintFlow=y", 0)); // $hasTaintFlow=y + sink(StringUtils.splitByCharacterType(taint())); // $hasTaintFlow=y + sink(StringUtils.splitByCharacterTypeCamelCase(taint())); // $hasTaintFlow=y + sink(StringUtils.splitByWholeSeparator(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.splitByWholeSeparator(taint(), "separator", 0)); // $hasTaintFlow=y + sink(StringUtils.splitByWholeSeparatorPreserveAllTokens(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.splitByWholeSeparatorPreserveAllTokens(taint(), "separator", 0)); // $hasTaintFlow=y + sink(StringUtils.splitPreserveAllTokens(taint())); // $hasTaintFlow=y + sink(StringUtils.splitPreserveAllTokens(taint(), ' ')); // $hasTaintFlow=y + sink(StringUtils.splitPreserveAllTokens(taint(), " ,;")); // $hasTaintFlow=y + sink(StringUtils.splitPreserveAllTokens(taint(), " ,;", 0)); // $hasTaintFlow=y + // GOOD (next 8 calls): separators don't propagate to the return value + sink(StringUtils.split("to split", taint())); + sink(StringUtils.split("to split", taint(), 0)); + sink(StringUtils.splitPreserveAllTokens("to split", taint(), 0)); + sink(StringUtils.splitByWholeSeparator("to split", taint())); + sink(StringUtils.splitByWholeSeparator("to split", taint(), 0)); + sink(StringUtils.splitByWholeSeparatorPreserveAllTokens("to split", taint())); + sink(StringUtils.splitByWholeSeparatorPreserveAllTokens("to split", taint(), 0)); + sink(StringUtils.splitPreserveAllTokens("to split", taint())); + sink(StringUtils.strip(taint())); // $hasTaintFlow=y + sink(StringUtils.strip(taint(), "charstoremove")); // $hasTaintFlow=y + sink(StringUtils.stripAccents(taint())); // $hasTaintFlow=y + sink(StringUtils.stripAll(new String[] { taint() }, "charstoremove")); // $hasTaintFlow=y + sink(StringUtils.stripEnd(taint(), "charstoremove")); // $hasTaintFlow=y + sink(StringUtils.stripStart(taint(), "charstoremove")); // $hasTaintFlow=y + // GOOD (next 4 calls): stripped chars do not flow to the return value. + sink(StringUtils.strip("original text", taint())); + sink(StringUtils.stripAll(new String[] { "original text" }, taint())); + sink(StringUtils.stripEnd("original text", taint())); + sink(StringUtils.stripStart("original text", taint())); + sink(StringUtils.stripToEmpty(taint())); // $hasTaintFlow=y + sink(StringUtils.stripToNull(taint())); // $hasTaintFlow=y + sink(StringUtils.substring(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.substring(taint(), 0, 0)); // $hasTaintFlow=y + sink(StringUtils.substringAfter(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.substringAfter(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.substringAfterLast(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.substringAfterLast(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.substringBefore(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.substringBeforeLast(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.substringBetween(taint(), "separator")); // $hasTaintFlow=y + sink(StringUtils.substringBetween(taint(), "start-tag", "end-tag")); // $hasTaintFlow=y + sink(StringUtils.substringsBetween(taint(), "start-tag", "end-tag")[0]); // $hasTaintFlow=y + // GOOD (next 9 calls): separators and bounding tags do not flow to the return value. + sink(StringUtils.substringAfter("original text", taint())); + sink(StringUtils.substringAfterLast("original text", taint())); + sink(StringUtils.substringBefore("original text", taint())); + sink(StringUtils.substringBeforeLast("original text", taint())); + sink(StringUtils.substringBetween("original text", taint())); + sink(StringUtils.substringBetween("original text", taint(), "end-tag")); + sink(StringUtils.substringBetween("original text", "start-tag", taint())); + sink(StringUtils.substringsBetween("original text", taint(), "end-tag")[0]); + sink(StringUtils.substringsBetween("original text", "start-tag", taint())[0]); + sink(StringUtils.swapCase(taint())); // $hasTaintFlow=y + sink(StringUtils.toCodePoints(taint())); // $hasTaintFlow=y + sink(StringUtils.toEncodedString(StringUtils.getBytes(taint(), "charset"), null)); // $hasTaintFlow=y + sink(StringUtils.toRootLowerCase(taint())); // $hasTaintFlow=y + sink(StringUtils.toRootUpperCase(taint())); // $hasTaintFlow=y + sink(StringUtils.toString(StringUtils.getBytes(taint(), "charset"), "charset")); // $hasTaintFlow=y + sink(StringUtils.trim(taint())); // $hasTaintFlow=y + sink(StringUtils.trimToEmpty(taint())); // $hasTaintFlow=y + sink(StringUtils.trimToNull(taint())); // $hasTaintFlow=y + sink(StringUtils.truncate(taint(), 0)); // $hasTaintFlow=y + sink(StringUtils.truncate(taint(), 0, 0)); // $hasTaintFlow=y + sink(StringUtils.uncapitalize(taint())); // $hasTaintFlow=y + sink(StringUtils.unwrap(taint(), '"')); // $hasTaintFlow=y + sink(StringUtils.unwrap(taint(), "separator")); // $hasTaintFlow=y + // GOOD: the wrapper string does not flow to the return value. + sink(StringUtils.unwrap("original string", taint())); + sink(StringUtils.upperCase(taint())); // $hasTaintFlow=y + sink(StringUtils.upperCase(taint(), null)); // $hasTaintFlow=y + sink(StringUtils.valueOf(taint().toCharArray())); // $hasTaintFlow=y + sink(StringUtils.wrap(taint(), '"')); // $hasTaintFlow=y + sink(StringUtils.wrap(taint(), "wrapper token")); // $hasTaintFlow=y + sink(StringUtils.wrap("wrap me", taint())); // $hasTaintFlow=y + sink(StringUtils.wrapIfMissing(taint(), '"')); // $hasTaintFlow=y + sink(StringUtils.wrapIfMissing(taint(), "wrapper token")); // $hasTaintFlow=y + sink(StringUtils.wrapIfMissing("wrap me", taint())); // $hasTaintFlow=y + + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..e69de29bb2d 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 new file mode 100644 index 00000000000..110a4e96689 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/flow.ql @@ -0,0 +1,30 @@ +import java +import semmle.code.java.dataflow.TaintTracking +import TestUtilities.InlineExpectationsTest + +class Conf extends TaintTracking::Configuration { + Conf() { this = "qltest:frameworks:apache-commons-lang3" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(MethodAccess).getMethod().hasName("taint") + } + + override predicate isSink(DataFlow::Node n) { + exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument()) + } +} + +class HasFlowTest extends InlineExpectationsTest { + HasFlowTest() { this = "HasFlowTest" } + + override string getARelevantTag() { result = "hasTaintFlow" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink, Conf conf | conf.hasFlow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + value = "y" + ) + } +} diff --git a/java/ql/test/library-tests/frameworks/apache-commons-lang3/options b/java/ql/test/library-tests/frameworks/apache-commons-lang3/options new file mode 100644 index 00000000000..8479c3984d7 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-commons-lang3/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-lang3-3.7 diff --git a/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java new file mode 100644 index 00000000000..800b62a545b --- /dev/null +++ b/java/ql/test/stubs/apache-commons-lang3-3.7/org/apache/commons/lang3/StringUtils.java @@ -0,0 +1,963 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.lang3; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.text.Normalizer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.Set; +import java.util.StringJoiner; +import java.util.function.Supplier; +import java.util.regex.Pattern; + + +public class StringUtils { + public static String abbreviate(final String str, final int maxWidth) { + return null; + } + + public static String abbreviate(final String str, final int offset, final int maxWidth) { + return null; + } + + public static String abbreviate(final String str, final String abbrevMarker, final int maxWidth) { + return null; + } + + public static String abbreviate(final String str, final String abbrevMarker, int offset, final int maxWidth) { + return null; + } + + public static String abbreviateMiddle(final String str, final String middle, final int length) { + return null; + } + + public static String appendIfMissing(final String str, final CharSequence suffix, final CharSequence... suffixes) { + return null; + } + + public static String appendIfMissingIgnoreCase(final String str, final CharSequence suffix, final CharSequence... suffixes) { + return null; + } + + public static String capitalize(final String str) { + return null; + } + + public static String center(final String str, final int size) { + return null; + } + + public static String center(String str, final int size, final char padChar) { + return null; + } + + public static String center(String str, final int size, String padStr) { + return null; + } + + public static String chomp(final String str) { + return null; + } + + public static String chomp(final String str, final String separator) { + return null; + } + + public static String chop(final String str) { + return null; + } + + public static int compare(final String str1, final String str2) { + return 0; + } + + public static int compare(final String str1, final String str2, final boolean nullIsLess) { + return 0; + } + + public static int compareIgnoreCase(final String str1, final String str2) { + return 0; + } + + public static int compareIgnoreCase(final String str1, final String str2, final boolean nullIsLess) { + return 0; + } + + public static boolean contains(final CharSequence seq, final CharSequence searchSeq) { + return false; + } + + public static boolean contains(final CharSequence seq, final int searchChar) { + return false; + } + + public static boolean containsAny(final CharSequence cs, final char... searchChars) { + return false; + } + + public static boolean containsAny(final CharSequence cs, final CharSequence searchChars) { + return false; + } + + public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences) { + return false; + } + + public static boolean containsAnyIgnoreCase(final CharSequence cs, final CharSequence... searchCharSequences) { + return false; + } + + public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr) { + return false; + } + + public static boolean containsNone(final CharSequence cs, final char... searchChars) { + return false; + } + + public static boolean containsNone(final CharSequence cs, final String invalidChars) { + return false; + } + + public static boolean containsOnly(final CharSequence cs, final char... valid) { + return false; + } + + public static boolean containsOnly(final CharSequence cs, final String validChars) { + return false; + } + + public static boolean containsWhitespace(final CharSequence seq) { + return false; + } + + public static int countMatches(final CharSequence str, final char ch) { + return 0; + } + + public static int countMatches(final CharSequence str, final CharSequence sub) { + return 0; + } + + public static T defaultIfBlank(final T str, final T defaultStr) { + return null; + } + + public static T defaultIfEmpty(final T str, final T defaultStr) { + return null; + } + + public static String defaultString(final String str) { + return null; + } + + public static String defaultString(final String str, final String defaultStr) { + return null; + } + + public static String deleteWhitespace(final String str) { + return null; + } + + public static String difference(final String str1, final String str2) { + return null; + } + + public static boolean endsWith(final CharSequence str, final CharSequence suffix) { + return false; + } + + public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { + return false; + } + + public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix) { + return false; + } + + public static boolean equals(final CharSequence cs1, final CharSequence cs2) { + return false; + } + + public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings) { + return false; + } + + public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence...searchStrings) { + return false; + } + + public static boolean equalsIgnoreCase(final CharSequence cs1, final CharSequence cs2) { + return false; + } + + public static T firstNonBlank(final T... values) { + return null; + } + + public static T firstNonEmpty(final T... values) { + return null; + } + + public static byte[] getBytes(final String string, final Charset charset) { + return null; + } + + public static byte[] getBytes(final String string, final String charset) throws UnsupportedEncodingException { + return null; + } + + public static String getCommonPrefix(final String... strs) { + return null; + } + + public static String getDigits(final String str) { + return null; + } + + public static int getFuzzyDistance(final CharSequence term, final CharSequence query, final Locale locale) { + return 0; + } + + public static T getIfBlank(final T str, final Supplier defaultSupplier) { + return null; + } + + public static T getIfEmpty(final T str, final Supplier defaultSupplier) { + return null; + } + + public static double getJaroWinklerDistance(final CharSequence first, final CharSequence second) { + return 0; + } + + public static int getLevenshteinDistance(CharSequence s, CharSequence t) { + return 0; + } + + public static int getLevenshteinDistance(CharSequence s, CharSequence t, final int threshold) { + return 0; + } + + public static int indexOf(final CharSequence seq, final CharSequence searchSeq) { + return 0; + } + + public static int indexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { + return 0; + } + + public static int indexOf(final CharSequence seq, final int searchChar) { + return 0; + } + + public static int indexOf(final CharSequence seq, final int searchChar, final int startPos) { + return 0; + } + + public static int indexOfAny(final CharSequence cs, final char... searchChars) { + return 0; + } + + public static int indexOfAny(final CharSequence str, final CharSequence... searchStrs) { + return 0; + } + + public static int indexOfAny(final CharSequence cs, final String searchChars) { + return 0; + } + + public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) { + return 0; + } + + public static int indexOfAnyBut(final CharSequence seq, final CharSequence searchChars) { + return 0; + } + + public static int indexOfDifference(final CharSequence... css) { + return 0; + } + + public static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { + return 0; + } + + public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { + return 0; + } + + public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { + return 0; + } + + public static boolean isAllBlank(final CharSequence... css) { + return false; + } + + public static boolean isAllEmpty(final CharSequence... css) { + return false; + } + + public static boolean isAllLowerCase(final CharSequence cs) { + return false; + } + + public static boolean isAllUpperCase(final CharSequence cs) { + return false; + } + + public static boolean isAlpha(final CharSequence cs) { + return false; + } + + public static boolean isAlphanumeric(final CharSequence cs) { + return false; + } + + public static boolean isAlphanumericSpace(final CharSequence cs) { + return false; + } + + public static boolean isAlphaSpace(final CharSequence cs) { + return false; + } + + public static boolean isAnyBlank(final CharSequence... css) { + return false; + } + + public static boolean isAnyEmpty(final CharSequence... css) { + return false; + } + + public static boolean isAsciiPrintable(final CharSequence cs) { + return false; + } + + public static boolean isBlank(final CharSequence cs) { + return false; + } + + public static boolean isEmpty(final CharSequence cs) { + return false; + } + + public static boolean isMixedCase(final CharSequence cs) { + return false; + } + + public static boolean isNoneBlank(final CharSequence... css) { + return false; + } + + public static boolean isNoneEmpty(final CharSequence... css) { + return false; + } + + public static boolean isNotBlank(final CharSequence cs) { + return false; + } + + public static boolean isNotEmpty(final CharSequence cs) { + return false; + } + + public static boolean isNumeric(final CharSequence cs) { + return false; + } + + public static boolean isNumericSpace(final CharSequence cs) { + return false; + } + + public static boolean isWhitespace(final CharSequence cs) { + return false; + } + + public static String join(final boolean[] array, final char delimiter) { + return null; + } + + public static String join(final boolean[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final byte[] array, final char delimiter) { + return null; + } + + public static String join(final byte[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final char[] array, final char delimiter) { + return null; + } + + public static String join(final char[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final double[] array, final char delimiter) { + return null; + } + + public static String join(final double[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final float[] array, final char delimiter) { + return null; + } + + public static String join(final float[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final int[] array, final char separator) { + return null; + } + + public static String join(final int[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final Iterable iterable, final char separator) { + return null; + } + + public static String join(final Iterable iterable, final String separator) { + return null; + } + + public static String join(final Iterator iterator, final char separator) { + return null; + } + + public static String join(final Iterator iterator, final String separator) { + return null; + } + + public static String join(final List list, final char separator, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final List list, final String separator, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final long[] array, final char separator) { + return null; + } + + public static String join(final long[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final Object[] array, final char delimiter) { + return null; + } + + public static String join(final Object[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final Object[] array, final String delimiter) { + return null; + } + + public static String join(final Object[] array, String delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final short[] array, final char delimiter) { + return null; + } + + public static String join(final short[] array, final char delimiter, final int startIndex, final int endIndex) { + return null; + } + + public static String join(final T... elements) { + return null; + } + + public static String joinWith(final String delimiter, final Object... array) { + return null; + } + + public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq) { + return 0; + } + + public static int lastIndexOf(final CharSequence seq, final CharSequence searchSeq, final int startPos) { + return 0; + } + + public static int lastIndexOf(final CharSequence seq, final int searchChar) { + return 0; + } + + public static int lastIndexOf(final CharSequence seq, final int searchChar, final int startPos) { + return 0; + } + + public static int lastIndexOfAny(final CharSequence str, final CharSequence... searchStrs) { + return 0; + } + + public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr) { + return 0; + } + + public static int lastIndexOfIgnoreCase(final CharSequence str, final CharSequence searchStr, int startPos) { + return 0; + } + + public static int lastOrdinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { + return 0; + } + + public static String left(final String str, final int len) { + return null; + } + + public static String leftPad(final String str, final int size) { + return null; + } + + public static String leftPad(final String str, final int size, final char padChar) { + return null; + } + + public static String leftPad(final String str, final int size, String padStr) { + return null; + } + + public static int length(final CharSequence cs) { + return 0; + } + + public static String lowerCase(final String str) { + return null; + } + + public static String lowerCase(final String str, final Locale locale) { + return null; + } + + public static String mid(final String str, int pos, final int len) { + return null; + } + + public static String normalizeSpace(final String str) { + return null; + } + + public static int ordinalIndexOf(final CharSequence str, final CharSequence searchStr, final int ordinal) { + return 0; + } + + public static String overlay(final String str, String overlay, int start, int end) { + return null; + } + + public static String prependIfMissing(final String str, final CharSequence prefix, final CharSequence... prefixes) { + return null; + } + + public static String prependIfMissingIgnoreCase(final String str, final CharSequence prefix, final CharSequence... prefixes) { + return null; + } + + public static String remove(final String str, final char remove) { + return null; + } + + public static String remove(final String str, final String remove) { + return null; + } + + public static String removeAll(final String text, final String regex) { + return null; + } + + public static String removeEnd(final String str, final String remove) { + return null; + } + + public static String removeEndIgnoreCase(final String str, final String remove) { + return null; + } + + public static String removeFirst(final String text, final String regex) { + return null; + } + + public static String removeIgnoreCase(final String str, final String remove) { + return null; + } + + public static String removePattern(final String source, final String regex) { + return null; + } + + public static String removeStart(final String str, final String remove) { + return null; + } + + public static String removeStartIgnoreCase(final String str, final String remove) { + return null; + } + + public static String repeat(final char ch, final int repeat) { + return null; + } + + public static String repeat(final String str, final int repeat) { + return null; + } + + public static String repeat(final String str, final String separator, final int repeat) { + return null; + } + + public static String replace(final String text, final String searchString, final String replacement) { + return null; + } + + public static String replace(final String text, final String searchString, final String replacement, final int max) { + return null; + } + + public static String replaceAll(final String text, final String regex, final String replacement) { + return null; + } + + public static String replaceChars(final String str, final char searchChar, final char replaceChar) { + return null; + } + + public static String replaceChars(final String str, final String searchChars, String replaceChars) { + return null; + } + + public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { + return null; + } + + public static String replaceEachRepeatedly(final String text, final String[] searchList, final String[] replacementList) { + return null; + } + + public static String replaceFirst(final String text, final String regex, final String replacement) { + return null; + } + + public static String replaceIgnoreCase(final String text, final String searchString, final String replacement) { + return null; + } + + public static String replaceIgnoreCase(final String text, final String searchString, final String replacement, final int max) { + return null; + } + + public static String replaceOnce(final String text, final String searchString, final String replacement) { + return null; + } + + public static String replaceOnceIgnoreCase(final String text, final String searchString, final String replacement) { + return null; + } + + public static String replacePattern(final String source, final String regex, final String replacement) { + return null; + } + + public static String reverse(final String str) { + return null; + } + + public static String reverseDelimited(final String str, final char separatorChar) { + return null; + } + + public static String right(final String str, final int len) { + return null; + } + + public static String rightPad(final String str, final int size) { + return null; + } + + public static String rightPad(final String str, final int size, final char padChar) { + return null; + } + + public static String rightPad(final String str, final int size, String padStr) { + return null; + } + + public static String rotate(final String str, final int shift) { + return null; + } + + public static String[] split(final String str) { + return null; + } + + public static String[] split(final String str, final char separatorChar) { + return null; + } + + public static String[] split(final String str, final String separatorChars) { + return null; + } + + public static String[] split(final String str, final String separatorChars, final int max) { + return null; + } + + public static String[] splitByCharacterType(final String str) { + return null; + } + + public static String[] splitByCharacterTypeCamelCase(final String str) { + return null; + } + + public static String[] splitByWholeSeparator(final String str, final String separator) { + return null; + } + + public static String[] splitByWholeSeparator( final String str, final String separator, final int max) { + return null; + } + + public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator) { + return null; + } + + public static String[] splitByWholeSeparatorPreserveAllTokens(final String str, final String separator, final int max) { + return null; + } + + public static String[] splitPreserveAllTokens(final String str) { + return null; + } + + public static String[] splitPreserveAllTokens(final String str, final char separatorChar) { + return null; + } + + public static String[] splitPreserveAllTokens(final String str, final String separatorChars) { + return null; + } + + public static String[] splitPreserveAllTokens(final String str, final String separatorChars, final int max) { + return null; + } + + public static boolean startsWith(final CharSequence str, final CharSequence prefix) { + return false; + } + + public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings) { + return false; + } + + public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix) { + return false; + } + + public static String strip(final String str) { + return null; + } + + public static String strip(String str, final String stripChars) { + return null; + } + + public static String stripAccents(final String input) { + return null; + } + + public static String[] stripAll(final String... strs) { + return null; + } + + public static String[] stripAll(final String[] strs, final String stripChars) { + return null; + } + + public static String stripEnd(final String str, final String stripChars) { + return null; + } + + public static String stripStart(final String str, final String stripChars) { + return null; + } + + public static String stripToEmpty(final String str) { + return null; + } + + public static String stripToNull(String str) { + return null; + } + + public static String substring(final String str, int start) { + return null; + } + + public static String substring(final String str, int start, int end) { + return null; + } + + public static String substringAfter(final String str, final int separator) { + return null; + } + + public static String substringAfter(final String str, final String separator) { + return null; + } + + public static String substringAfterLast(final String str, final int separator) { + return null; + } + + public static String substringAfterLast(final String str, final String separator) { + return null; + } + + public static String substringBefore(final String str, final String separator) { + return null; + } + + public static String substringBeforeLast(final String str, final String separator) { + return null; + } + + public static String substringBetween(final String str, final String tag) { + return null; + } + + public static String substringBetween(final String str, final String open, final String close) { + return null; + } + + public static String[] substringsBetween(final String str, final String open, final String close) { + return null; + } + + public static String swapCase(final String str) { + return null; + } + + public static int[] toCodePoints(final CharSequence cs) { + return null; + } + + public static String toEncodedString(final byte[] bytes, final Charset charset) { + return null; + } + + public static String toRootLowerCase(final String source) { + return null; + } + + public static String toRootUpperCase(final String source) { + return null; + } + + public static String toString(final byte[] bytes, final String charsetName) throws UnsupportedEncodingException { + return null; + } + + public static String trim(final String str) { + return null; + } + + public static String trimToEmpty(final String str) { + return null; + } + + public static String trimToNull(final String str) { + return null; + } + + public static String truncate(final String str, final int maxWidth) { + return null; + } + + public static String truncate(final String str, final int offset, final int maxWidth) { + return null; + } + + public static String uncapitalize(final String str) { + return null; + } + + public static String unwrap(final String str, final char wrapChar) { + return null; + } + + public static String unwrap(final String str, final String wrapToken) { + return null; + } + + public static String upperCase(final String str) { + return null; + } + + public static String upperCase(final String str, final Locale locale) { + return null; + } + + public static String valueOf(final char[] value) { + return null; + } + + public static String wrap(final String str, final char wrapWith) { + return null; + } + + public static String wrap(final String str, final String wrapWith) { + return null; + } + + public static String wrapIfMissing(final String str, final char wrapWith) { + return null; + } + + public static String wrapIfMissing(final String str, final String wrapWith) { + return null; + } + + public StringUtils() { + } + +} From 552f0a7c5e435ec17c6db04214b913c160a32a6e Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 15:55:41 +0000 Subject: [PATCH 405/429] C++: Address review. --- cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll index ae3fab9f077..aecd98981e8 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdMap.qll @@ -150,7 +150,7 @@ private class StdMapFind extends TaintFunction { * The standard map `erase` function. */ private class StdMapErase extends TaintFunction { - StdMapErase() { this.getCLassAndName("erase") instanceof MapOrUnorderedMap } + StdMapErase() { this.getClassAndName("erase") instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from qualifier to iterator return value @@ -165,8 +165,7 @@ private class StdMapErase extends TaintFunction { */ private class StdMapEqualRange extends TaintFunction { StdMapEqualRange() { - this.hasName(["lower_bound", "upper_bound", "equal_range"]) and - this.getDeclaringType() instanceof MapOrUnorderedMap + this.getClassAndName(["lower_bound", "upper_bound", "equal_range"]) instanceof MapOrUnorderedMap } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From a04883cafcdb29c8b910cde2adbb053a6ec0a37d Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 16:17:59 +0000 Subject: [PATCH 406/429] C++: Fix compilation. --- .../src/semmle/code/cpp/models/implementations/StdContainer.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll index f416d8e9810..9176c6c3a1a 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -113,7 +113,7 @@ private class StdSequenceContainerPush extends TaintFunction { this.getClassAndName("push_back") instanceof Array or this.getClassAndName(["push_back", "push_front"]) instanceof Deque or this.getClassAndName("push_front") instanceof ForwardList or - this.getClassAndName("push_back") instanceof List or + this.getClassAndName("push_back") instanceof List } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From 3fb42194a5e4a134b34e2ed6dedd48dce5acabce Mon Sep 17 00:00:00 2001 From: Cornelius Riemenschneider Date: Tue, 16 Feb 2021 17:58:45 +0100 Subject: [PATCH 407/429] Apply suggestions from code review Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- .../semmle/code/cpp/models/implementations/StdContainer.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll index 9176c6c3a1a..367db1613fc 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -110,10 +110,10 @@ private class StdSequenceContainerData extends TaintFunction { */ private class StdSequenceContainerPush extends TaintFunction { StdSequenceContainerPush() { - this.getClassAndName("push_back") instanceof Array or + this.getClassAndName("push_back") instanceof Vector or this.getClassAndName(["push_back", "push_front"]) instanceof Deque or this.getClassAndName("push_front") instanceof ForwardList or - this.getClassAndName("push_back") instanceof List + this.getClassAndName(["push_back", "push_front"]) instanceof List } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From 735e014b435269d4e6cd6ad6b4696f160d0bfa96 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:22:59 +0000 Subject: [PATCH 408/429] C++: Model BSL in Gets.qll. --- cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll index f698a1209f4..08222c2cd6a 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Gets.qll @@ -19,7 +19,7 @@ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunctio // gets(str) // fgets(str, num, stream) // fgetws(wstr, num, stream) - hasGlobalOrStdName(["gets", "fgets", "fgetws"]) + hasGlobalOrStdOrBslName(["gets", "fgets", "fgetws"]) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { @@ -54,13 +54,13 @@ private class GetsFunction extends DataFlowFunction, TaintFunction, ArrayFunctio } override predicate hasArrayWithVariableSize(int bufParam, int countParam) { - not hasGlobalOrStdName("gets") and + not hasName("gets") and bufParam = 0 and countParam = 1 } override predicate hasArrayWithUnknownSize(int bufParam) { - hasGlobalOrStdName("gets") and + hasName("gets") and bufParam = 0 } From 04eb0c774cb6456106b26967fb093b89b62ecc2e Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Tue, 16 Feb 2021 18:25:54 +0100 Subject: [PATCH 409/429] Python: Use `LocalSourceNode` in type tracker tests One minor change to the tests results needed: there is no longer local flow going into the `ModuleVariableNode` for `attr_ref` in the `moduleattr.ql` test, but I think this is reasonable. --- .../dataflow/typetracking/moduleattr.expected | 1 - .../dataflow/typetracking/moduleattr.ql | 10 ++++--- .../dataflow/typetracking/tracked.ql | 28 +++++++++---------- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/python/ql/test/experimental/dataflow/typetracking/moduleattr.expected b/python/ql/test/experimental/dataflow/typetracking/moduleattr.expected index adfc8c5a379..82aa6e99c3c 100644 --- a/python/ql/test/experimental/dataflow/typetracking/moduleattr.expected +++ b/python/ql/test/experimental/dataflow/typetracking/moduleattr.expected @@ -1,7 +1,6 @@ module_tracker | import_as_attr.py:1:6:1:11 | ControlFlowNode for ImportExpr | module_attr_tracker -| import_as_attr.py:0:0:0:0 | ModuleVariableNode for Global Variable attr_ref in Module import_as_attr | | import_as_attr.py:1:20:1:35 | ControlFlowNode for ImportMember | | import_as_attr.py:1:28:1:35 | GSSA Variable attr_ref | | import_as_attr.py:3:1:3:1 | GSSA Variable x | diff --git a/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql b/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql index 1d3430493ab..b546dc7491d 100644 --- a/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql +++ b/python/ql/test/experimental/dataflow/typetracking/moduleattr.ql @@ -2,16 +2,18 @@ import python import semmle.python.dataflow.new.DataFlow import semmle.python.dataflow.new.TypeTracker -DataFlow::Node module_tracker(TypeTracker t) { +DataFlow::LocalSourceNode module_tracker(TypeTracker t) { t.start() and result = DataFlow::importNode("module") or exists(TypeTracker t2 | result = module_tracker(t2).track(t2, t)) } -query DataFlow::Node module_tracker() { result = module_tracker(DataFlow::TypeTracker::end()) } +query DataFlow::Node module_tracker() { + module_tracker(DataFlow::TypeTracker::end()).flowsTo(result) +} -DataFlow::Node module_attr_tracker(TypeTracker t) { +DataFlow::LocalSourceNode module_attr_tracker(TypeTracker t) { t.startInAttr("attr") and result = module_tracker() or @@ -19,5 +21,5 @@ DataFlow::Node module_attr_tracker(TypeTracker t) { } query DataFlow::Node module_attr_tracker() { - result = module_attr_tracker(DataFlow::TypeTracker::end()) + module_attr_tracker(DataFlow::TypeTracker::end()).flowsTo(result) } diff --git a/python/ql/test/experimental/dataflow/typetracking/tracked.ql b/python/ql/test/experimental/dataflow/typetracking/tracked.ql index 0797e484c97..91ffe7e47c1 100644 --- a/python/ql/test/experimental/dataflow/typetracking/tracked.ql +++ b/python/ql/test/experimental/dataflow/typetracking/tracked.ql @@ -6,7 +6,7 @@ import TestUtilities.InlineExpectationsTest // ----------------------------------------------------------------------------- // tracked // ----------------------------------------------------------------------------- -DataFlow::Node tracked(TypeTracker t) { +DataFlow::LocalSourceNode tracked(TypeTracker t) { t.start() and result.asCfgNode() = any(NameNode n | n.getId() = "tracked") or @@ -20,7 +20,7 @@ class TrackedTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | - e = tracked(t) 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 @@ -34,14 +34,14 @@ class TrackedTest extends InlineExpectationsTest { // ----------------------------------------------------------------------------- // int + str // ----------------------------------------------------------------------------- -DataFlow::Node int_type(TypeTracker t) { +DataFlow::LocalSourceNode int_type(TypeTracker t) { t.start() and result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "int") or exists(TypeTracker t2 | result = int_type(t2).track(t2, t)) } -DataFlow::Node string_type(TypeTracker t) { +DataFlow::LocalSourceNode string_type(TypeTracker t) { t.start() and result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "str") or @@ -55,7 +55,7 @@ class TrackedIntTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | - e = int_type(t) and + int_type(t).flowsTo(e) and tag = "int" and location = e.getLocation() and value = t.getAttr() and @@ -71,7 +71,7 @@ class TrackedStringTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | - e = string_type(t) and + string_type(t).flowsTo(e) and tag = "str" and location = e.getLocation() and value = t.getAttr() and @@ -83,7 +83,7 @@ class TrackedStringTest extends InlineExpectationsTest { // ----------------------------------------------------------------------------- // tracked_self // ----------------------------------------------------------------------------- -DataFlow::Node tracked_self(TypeTracker t) { +DataFlow::LocalSourceNode tracked_self(TypeTracker t) { t.start() and exists(Function f | f.isMethod() and @@ -101,7 +101,7 @@ class TrackedSelfTest extends InlineExpectationsTest { override predicate hasActualResult(Location location, string element, string tag, string value) { exists(DataFlow::Node e, TypeTracker t | - e = tracked_self(t) and + tracked_self(t).flowsTo(e) and // Module variables have no sensible location, and hence can't be annotated. not e instanceof DataFlow::ModuleVariableNode and tag = "tracked_self" and @@ -117,7 +117,7 @@ class TrackedSelfTest extends InlineExpectationsTest { // ----------------------------------------------------------------------------- // This modeling follows the same pattern that we currently use in our real library modeling. /** Gets a reference to `foo` (fictive module). */ -private DataFlow::Node foo(DataFlow::TypeTracker t) { +private DataFlow::LocalSourceNode foo(DataFlow::TypeTracker t) { t.start() and result = DataFlow::importNode("foo") or @@ -125,10 +125,10 @@ private DataFlow::Node foo(DataFlow::TypeTracker t) { } /** Gets a reference to `foo` (fictive module). */ -DataFlow::Node foo() { result = foo(DataFlow::TypeTracker::end()) } +DataFlow::Node foo() { foo(DataFlow::TypeTracker::end()).flowsTo(result) } /** Gets a reference to `foo.bar` (fictive module). */ -private DataFlow::Node foo_bar(DataFlow::TypeTracker t) { +private DataFlow::LocalSourceNode foo_bar(DataFlow::TypeTracker t) { t.start() and result = DataFlow::importNode("foo.bar") or @@ -139,10 +139,10 @@ private DataFlow::Node foo_bar(DataFlow::TypeTracker t) { } /** Gets a reference to `foo.bar` (fictive module). */ -DataFlow::Node foo_bar() { result = foo_bar(DataFlow::TypeTracker::end()) } +DataFlow::Node foo_bar() { foo_bar(DataFlow::TypeTracker::end()).flowsTo(result) } /** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */ -private DataFlow::Node foo_bar_baz(DataFlow::TypeTracker t) { +private DataFlow::LocalSourceNode foo_bar_baz(DataFlow::TypeTracker t) { t.start() and result = DataFlow::importNode("foo.bar.baz") or @@ -153,7 +153,7 @@ private DataFlow::Node foo_bar_baz(DataFlow::TypeTracker t) { } /** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */ -DataFlow::Node foo_bar_baz() { result = foo_bar_baz(DataFlow::TypeTracker::end()) } +DataFlow::Node foo_bar_baz() { foo_bar_baz(DataFlow::TypeTracker::end()).flowsTo(result) } class TrackedFooBarBaz extends InlineExpectationsTest { TrackedFooBarBaz() { this = "TrackedFooBarBaz" } From e17d539883965f781698ebdd92d1dcb104921e7f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Feb 2021 17:56:48 +0000 Subject: [PATCH 410/429] C++: Model BSL in Getenv.qll. --- cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll index 93b601de752..87e191241d2 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Getenv.qll @@ -9,7 +9,7 @@ import semmle.code.cpp.models.interfaces.FlowSource * The POSIX function `getenv`. */ class Getenv extends LocalFlowSourceFunction { - Getenv() { this.hasGlobalName("getenv") } + Getenv() { this.hasGlobalOrStdOrBslName("getenv") } override predicate hasLocalFlowSource(FunctionOutput output, string description) { ( From fa44cedd3804f4d43b4ad4157a09fefe7a92d513 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 16 Feb 2021 18:58:28 +0100 Subject: [PATCH 411/429] C++: Add isBarrier to CgiXss.ql. --- cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql | 4 +++ .../CWE/CWE-079/semmle/CgiXss/CgiXss.expected | 32 +++++++++---------- .../CWE/CWE-079/semmle/CgiXss/search.c | 20 +++++++++--- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql index 24484a9dcaf..d1e2fa12913 100644 --- a/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql +++ b/cpp/ql/src/Security/CWE/CWE-079/CgiXss.ql @@ -34,6 +34,10 @@ class Configuration extends TaintTrackingConfiguration { override predicate isSink(Element tainted) { exists(PrintStdoutCall call | call.getAnArgument() = tainted) } + + override predicate isBarrier(Expr e) { + super.isBarrier(e) or e.getUnspecifiedType() instanceof IntegralType + } } from QueryString query, Element printedArg, PathNode sourceNode, PathNode sinkNode diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected index 6f08104489e..de3326e74a5 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/CgiXss.expected @@ -8,14 +8,14 @@ edges | search.c:22:24:22:28 | *query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | | search.c:22:24:22:28 | query | search.c:23:39:23:43 | query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:14:24:14:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | *query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | -| search.c:41:21:41:26 | call to getenv | search.c:22:24:22:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:14:24:14:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | *query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | query | +| search.c:51:21:51:26 | call to getenv | search.c:22:24:22:28 | query | nodes | search.c:14:24:14:28 | *query | semmle.label | *query | | search.c:14:24:14:28 | query | semmle.label | query | @@ -29,12 +29,12 @@ nodes | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | | search.c:23:39:23:43 | query | semmle.label | query | -| search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | -| search.c:41:21:41:26 | call to getenv | semmle.label | call to getenv | -| search.c:45:5:45:15 | Argument 0 | semmle.label | Argument 0 | -| search.c:45:17:45:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | -| search.c:47:5:47:15 | Argument 0 | semmle.label | Argument 0 | -| search.c:47:17:47:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | +| search.c:51:21:51:26 | call to getenv | semmle.label | call to getenv | +| search.c:55:5:55:15 | Argument 0 | semmle.label | Argument 0 | +| search.c:55:17:55:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | +| search.c:57:5:57:15 | Argument 0 | semmle.label | Argument 0 | +| search.c:57:17:57:25 | Argument 0 indirection | semmle.label | Argument 0 indirection | #select -| search.c:17:8:17:12 | query | search.c:41:21:41:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | -| search.c:23:39:23:43 | query | search.c:41:21:41:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:41:21:41:26 | call to getenv | this query data | +| search.c:17:8:17:12 | query | search.c:51:21:51:26 | call to getenv | search.c:17:8:17:12 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data | +| search.c:23:39:23:43 | query | search.c:51:21:51:26 | call to getenv | search.c:23:39:23:43 | query | Cross-site scripting vulnerability due to $@. | search.c:51:21:51:26 | call to getenv | this query data | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c index df9a09ded59..987535fcafc 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c @@ -26,7 +26,7 @@ void bad_server2(char* query) { puts(do_search(query)); } -void good_server(char* query) { +void good_server1(char* query) { puts("

    Query results for "); // GOOD: Escape HTML characters before adding to a page char* query_escaped = escape_html(query); @@ -37,14 +37,26 @@ void good_server(char* query) { puts(do_search(query)); } +int snprintf(char *, int, const char *, ...); + +void good_server2(char* query) { + puts("

    Query results for "); + // GOOD: Only an integer is added to the page. + int i = 0; + snprintf(query, 16, "value=%i", &i); + printf("\n

    %i

    \n", i); +} + int main(int argc, char** argv) { char* raw_query = getenv("QUERY_STRING"); - if (strcmp("good", argv[0]) == 0) { - good_server(raw_query); + if (strcmp("good1", argv[0]) == 0) { + good_server1(raw_query); } else if (strcmp("bad1", argv[0]) == 0) { bad_server1(raw_query); - } else { + } else if (strcmp("bad2", argv[0]) == 0) { bad_server2(raw_query); + } else if (strcmp("good2", argv[0]) == 0) { + good_server2(raw_query); } } From 58230d6d0a333266d6dc95feac6b67c0e7868073 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Feb 2021 18:00:23 +0000 Subject: [PATCH 412/429] C++: Model BSL in Fread.qll. --- cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll index 9524b18b0a2..df2d92fbc4f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Fread.qll @@ -2,7 +2,7 @@ import semmle.code.cpp.models.interfaces.Alias import semmle.code.cpp.models.interfaces.FlowSource private class Fread extends AliasFunction, RemoteFlowSourceFunction { - Fread() { this.hasGlobalName("fread") } + Fread() { this.hasGlobalOrStdOrBslName("fread") } override predicate parameterNeverEscapes(int n) { n = 0 or From 3323683ab2be20c349ff839a9391bc8bb7fa3f4f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 16 Feb 2021 19:10:39 +0000 Subject: [PATCH 413/429] C++: Support BSL in Allocation.qll, Deallocation.qll. --- .../semmle/code/cpp/models/implementations/Allocation.qll | 6 +++--- .../code/cpp/models/implementations/Deallocation.qll | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll index 91ec1525834..25dae1c2fd1 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Allocation.qll @@ -15,7 +15,7 @@ private class MallocAllocationFunction extends AllocationFunction { MallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdName("malloc") and // malloc(size) + hasGlobalOrStdOrBslName("malloc") and // malloc(size) sizeArg = 0 or hasGlobalName([ @@ -104,7 +104,7 @@ private class CallocAllocationFunction extends AllocationFunction { CallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdName("calloc") and // calloc(num, size) + hasGlobalOrStdOrBslName("calloc") and // calloc(num, size) sizeArg = 1 and multArg = 0 } @@ -124,7 +124,7 @@ private class ReallocAllocationFunction extends AllocationFunction { ReallocAllocationFunction() { // --- C library allocation - hasGlobalOrStdName("realloc") and // realloc(ptr, size) + hasGlobalOrStdOrBslName("realloc") and // realloc(ptr, size) sizeArg = 1 and reallocArg = 0 or diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll index b56c8c21949..6bd2916b733 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Deallocation.qll @@ -13,9 +13,13 @@ private class StandardDeallocationFunction extends DeallocationFunction { int freedArg; StandardDeallocationFunction() { - hasGlobalName([ + hasGlobalOrStdOrBslName([ // --- C library allocation - "free", "realloc", + "free", "realloc" + ]) and + freedArg = 0 + or + hasGlobalName([ // --- OpenSSL memory allocation "CRYPTO_free", "CRYPTO_secure_free" ]) and From d98aae9fc159c676f4649cfb7a24aa0620449553 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Tue, 16 Feb 2021 23:44:03 +0100 Subject: [PATCH 414/429] Python: Expose framework identifier for route-setup and req handler This makes collecting metrics on framework coverage a bit simpler (specifically giving the RoutedParameter class a more descriptive result for getSourceType). I guess it can also help a bit when trying to get an overview of a new DB, but making metrics collection easier is my main motivation for this. --- python/ql/src/semmle/python/Concepts.qll | 20 +++++++++++++++++-- .../src/semmle/python/frameworks/Django.qll | 4 ++++ .../ql/src/semmle/python/frameworks/Flask.qll | 4 ++++ .../src/semmle/python/frameworks/Stdlib.qll | 2 ++ .../src/semmle/python/frameworks/Tornado.qll | 6 +++++- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/Concepts.qll b/python/ql/src/semmle/python/Concepts.qll index b81817d7f10..c6d1ce367e9 100644 --- a/python/ql/src/semmle/python/Concepts.qll +++ b/python/ql/src/semmle/python/Concepts.qll @@ -325,6 +325,9 @@ module HTTP { * requests for this route, if any. These automatically become a `RemoteFlowSource`. */ Parameter getARoutedParameter() { result = range.getARoutedParameter() } + + /** Gets a string that identifies the framework used for this route setup. */ + string getFramework() { result = range.getFramework() } } /** Provides a class for modeling new HTTP routing APIs. */ @@ -359,6 +362,9 @@ module HTTP { * requests for this route, if any. These automatically become a `RemoteFlowSource`. */ abstract Parameter getARoutedParameter(); + + /** Gets a string that identifies the framework used for this route setup. */ + abstract string getFramework(); } } @@ -378,6 +384,9 @@ module HTTP { * requests, if any. These automatically become a `RemoteFlowSource`. */ Parameter getARoutedParameter() { result = range.getARoutedParameter() } + + /** Gets a string that identifies the framework used for this route setup. */ + string getFramework() { result = range.getFramework() } } /** Provides a class for modeling new HTTP request handlers. */ @@ -396,6 +405,9 @@ module HTTP { * requests, if any. These automatically become a `RemoteFlowSource`. */ abstract Parameter getARoutedParameter(); + + /** Gets a string that identifies the framework used for this request handler. */ + abstract string getFramework(); } } @@ -408,13 +420,17 @@ module HTTP { result = rs.getARoutedParameter() and result in [this.getArg(_), this.getArgByName(_)] } + + override string getFramework() { result = rs.getFramework() } } /** A parameter that will receive parts of the url when handling an incoming request. */ private class RoutedParameter extends RemoteFlowSource::Range, DataFlow::ParameterNode { - RoutedParameter() { this.getParameter() = any(RequestHandler handler).getARoutedParameter() } + RequestHandler handler; - override string getSourceType() { result = "RoutedParameter" } + RoutedParameter() { this.getParameter() = handler.getARoutedParameter() } + + override string getSourceType() { result = handler.getFramework() + " RoutedParameter" } } /** diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 6e90d5adee0..fb9a77e1adc 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2158,6 +2158,8 @@ private module Django { result = vc.getARequestHandler() ) } + + override string getFramework() { result = "Django" } } /** A request handler defined in a django view class, that has no known route. */ @@ -2175,6 +2177,8 @@ private module Django { result in [this.getArg(_), this.getArgByName(_)] and not result = any(int i | i <= this.getRequestParamIndex() | this.getArg(i)) } + + override string getFramework() { result = "Django" } } /** diff --git a/python/ql/src/semmle/python/frameworks/Flask.qll b/python/ql/src/semmle/python/frameworks/Flask.qll index fe394c6c8ac..c719291f3ca 100644 --- a/python/ql/src/semmle/python/frameworks/Flask.qll +++ b/python/ql/src/semmle/python/frameworks/Flask.qll @@ -219,6 +219,8 @@ private module FlaskModel { ) ) } + + override string getFramework() { result = "Flask" } } /** @@ -277,6 +279,8 @@ private module FlaskModel { result in [this.getArg(_), this.getArgByName(_)] and not result = this.getArg(0) } + + override string getFramework() { result = "Flask" } } // --------------------------------------------------------------------------- diff --git a/python/ql/src/semmle/python/frameworks/Stdlib.qll b/python/ql/src/semmle/python/frameworks/Stdlib.qll index 5120534d014..e4b5dc91827 100644 --- a/python/ql/src/semmle/python/frameworks/Stdlib.qll +++ b/python/ql/src/semmle/python/frameworks/Stdlib.qll @@ -1629,6 +1629,8 @@ private module Stdlib { } override Parameter getARoutedParameter() { none() } + + override string getFramework() { result = "Stdlib" } } } diff --git a/python/ql/src/semmle/python/frameworks/Tornado.qll b/python/ql/src/semmle/python/frameworks/Tornado.qll index 4351188d8bb..a43edcaca90 100644 --- a/python/ql/src/semmle/python/frameworks/Tornado.qll +++ b/python/ql/src/semmle/python/frameworks/Tornado.qll @@ -486,7 +486,9 @@ private module Tornado { } /** A tornado route setup. */ - abstract class TornadoRouteSetup extends HTTP::Server::RouteSetup::Range { } + abstract class TornadoRouteSetup extends HTTP::Server::RouteSetup::Range { + override string getFramework() { result = "Tornado" } + } /** * A regex that is used to set up a route. @@ -561,6 +563,8 @@ private module Tornado { result in [this.getArg(_), this.getArgByName(_)] and not result = this.getArg(0) } + + override string getFramework() { result = "Tornado" } } // --------------------------------------------------------------------------- From f5d5460dde1768b82c7ac21bd022d99f8d3e427e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 17 Feb 2021 10:53:31 +0100 Subject: [PATCH 415/429] C++: Fix testcase. --- .../query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c index 987535fcafc..fd24379b890 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c @@ -37,13 +37,13 @@ void good_server1(char* query) { puts(do_search(query)); } -int snprintf(char *, int, const char *, ...); +int scanf(const char *, ...); void good_server2(char* query) { puts("

    Query results for "); // GOOD: Only an integer is added to the page. int i = 0; - snprintf(query, 16, "value=%i", &i); + sscanf(query, "value=%i", &i); printf("\n

    %i

    \n", i); } From 2927d888cfb707df389b75626c07e35de7ad652d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 11:20:00 +0100 Subject: [PATCH 416/429] Python: Fix location of PathInjection tests --- .../Injection/{TarSlip => }/PathInjection/PathInjection.expected | 0 .../Injection/{TarSlip => }/PathInjection/PathInjection.qlref | 0 .../Injection/{TarSlip => }/PathInjection/path_injection.py | 0 .../Security/Injection/{TarSlip => }/PathInjection/test.py | 0 .../Injection/{TarSlip => }/PathInjection/test_chaining.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/query-tests/Security/Injection/{TarSlip => }/PathInjection/PathInjection.expected (100%) rename python/ql/test/query-tests/Security/Injection/{TarSlip => }/PathInjection/PathInjection.qlref (100%) rename python/ql/test/query-tests/Security/Injection/{TarSlip => }/PathInjection/path_injection.py (100%) rename python/ql/test/query-tests/Security/Injection/{TarSlip => }/PathInjection/test.py (100%) rename python/ql/test/query-tests/Security/Injection/{TarSlip => }/PathInjection/test_chaining.py (100%) diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.expected b/python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.expected rename to python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.expected diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.qlref b/python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.qlref similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/PathInjection.qlref rename to python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.qlref diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/path_injection.py b/python/ql/test/query-tests/Security/Injection/PathInjection/path_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/path_injection.py rename to python/ql/test/query-tests/Security/Injection/PathInjection/path_injection.py diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test.py b/python/ql/test/query-tests/Security/Injection/PathInjection/test.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test.py rename to python/ql/test/query-tests/Security/Injection/PathInjection/test.py diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test_chaining.py b/python/ql/test/query-tests/Security/Injection/PathInjection/test_chaining.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/PathInjection/test_chaining.py rename to python/ql/test/query-tests/Security/Injection/PathInjection/test_chaining.py From 1b148c4c906645873ce1fafa960eb0021f693386 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 17 Feb 2021 11:20:00 +0100 Subject: [PATCH 417/429] C++: Add reduced testcase demonstrating the problem in codeql-c-analysis-team/issues/231. --- .../dataflow/taint-tests/localTaint.expected | 15 +++++++++++ .../dataflow/taint-tests/taint.cpp | 26 +++++++++++++++++++ 2 files changed, 41 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 9f038101d67..02ebcd3e1b7 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -6042,6 +6042,21 @@ | taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:631:2:631:18 | ... = ... | | | taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:632:7:632:7 | c | | | taint.cpp:631:16:631:17 | | taint.cpp:631:6:631:14 | call to _strnextc | TAINT | +| taint.cpp:640:9:640:12 | this | taint.cpp:640:25:640:29 | this | | +| taint.cpp:643:33:643:38 | source | taint.cpp:645:20:645:25 | source | | +| taint.cpp:644:30:644:30 | c | taint.cpp:645:10:645:10 | c | | +| taint.cpp:644:30:644:30 | c | taint.cpp:646:8:646:8 | c | | +| taint.cpp:645:10:645:10 | ref arg c | taint.cpp:646:8:646:8 | c | | +| taint.cpp:645:12:645:15 | call to data | taint.cpp:645:3:645:8 | call to memcpy | | +| taint.cpp:645:20:645:25 | source | taint.cpp:645:3:645:8 | call to memcpy | TAINT | +| taint.cpp:645:20:645:25 | source | taint.cpp:645:12:645:15 | ref arg call to data | TAINT | +| taint.cpp:652:9:652:12 | this | taint.cpp:652:31:652:35 | this | | +| taint.cpp:655:35:655:40 | source | taint.cpp:657:20:657:25 | source | | +| taint.cpp:656:27:656:27 | c | taint.cpp:657:10:657:10 | c | | +| taint.cpp:656:27:656:27 | c | taint.cpp:658:8:658:8 | c | | +| taint.cpp:657:12:657:15 | call to data | taint.cpp:657:3:657:8 | call to memcpy | | +| taint.cpp:657:20:657:25 | source | taint.cpp:657:3:657:8 | call to memcpy | TAINT | +| taint.cpp:657:20:657:25 | source | taint.cpp:657:12:657:15 | ref arg call to data | TAINT | | 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 44d84c0c0b0..9a55aaaaaba 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -630,4 +630,30 @@ void test__strnextc(const char* source) { } while(c != '\0'); c = _strnextc(""); sink(c); +} + +// --- taint through const specified function --- + +class C_no_const_member_function { + char* data_; +public: + char* data() { return data_; } +}; + +void test_no_const_member(char* source) { + C_no_const_member_function c; + memcpy(c.data(), source, 16); + sink(c.data()); // $ ast MISSING: ir +} + +class C_const_member_function { + char* data_; +public: + char* data() const { return data_; } +}; + +void test_with_const_member(char* source) { + C_const_member_function c; + memcpy(c.data(), source, 16); + sink(c.data()); // $ MISSING: ast, ir } \ No newline at end of file From 1adb5105780859bd0ee57da7cad7258566edf2e7 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 11:24:11 +0100 Subject: [PATCH 418/429] Python: Add a single missing QLDoc --- python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll b/python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll index da52edd6af1..b3482012e9a 100644 --- a/python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll @@ -41,6 +41,7 @@ private import semmle.python.objects.ObjectInternal * A callable that is considered a "safe" external API from a security perspective. */ class SafeExternalAPI extends Unit { + /** Gets a callable that is considered a "safe" external API from a security perspective. */ abstract DataFlowPrivate::DataFlowCallable getSafeCallable(); } From dec026a820c8efa0813bf64145d01e60c8f9db13 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 11:26:02 +0100 Subject: [PATCH 419/429] Python: Fix security qlref to have single empty line --- .../BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref | 2 +- .../BadPractice/HardcodedCredentials/HardcodedCredentials.qlref | 2 +- .../IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref | 2 +- .../IncompleteUrlSubstringSanitization.qlref | 2 +- .../Exposure/SensitiveDataExposure/CleartextLogging.qlref | 2 +- .../Exposure/SensitiveDataExposure/CleartextStorage.qlref | 2 +- .../Security/Injection/OpenRedirect/UrlRedirect.qlref | 1 - 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref index 29aa18f4b41..adef42d0768 100644 --- a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref +++ b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref @@ -1 +1 @@ -Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql \ No newline at end of file +Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref index 9ced1d74449..ff70ade48e7 100644 --- a/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref +++ b/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref @@ -1 +1 @@ -Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql \ No newline at end of file +Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref index 7c132ddf232..2fac15c1228 100644 --- a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref +++ b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref @@ -1 +1 @@ -Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql \ No newline at end of file +Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref index f41c8ec32d5..00a3a8dad07 100644 --- a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref +++ b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref @@ -1 +1 @@ -Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql \ No newline at end of file +Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref index 176057d5c62..e6c1510a3b2 100644 --- a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref +++ b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref @@ -1 +1 @@ -Security/Exposure/SensitiveDataExposure/CleartextLogging.ql \ No newline at end of file +Security/Exposure/SensitiveDataExposure/CleartextLogging.ql diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref index 1feacb96d8c..63f1d245881 100644 --- a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref +++ b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref @@ -1 +1 @@ -Security/Exposure/SensitiveDataExposure/CleartextStorage.ql \ No newline at end of file +Security/Exposure/SensitiveDataExposure/CleartextStorage.ql diff --git a/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref b/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref index ce10eb1f21a..492b7a69453 100644 --- a/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref +++ b/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref @@ -1,2 +1 @@ Security/Injection/OpenRedirect/OpenRedirect.ql - From cf9ad0cdc5d88d128f95a5b19fc0fba62cbd242e Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 11:29:33 +0100 Subject: [PATCH 420/429] Python: Move ExternalAPI queries back under Security This was raised as a question at review, and I don't really have a good enough argument for moving it under POI. At the end of the day, they are _security_ related enough I guess :) --- .../src/{POI => Security}/ExternalAPIs/ExternalAPISinkExample.py | 0 .../ExternalAPIs/ExternalAPITaintStepExample.py | 0 python/ql/src/{POI => Security}/ExternalAPIs/ExternalAPIs.qll | 0 .../ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp | 0 .../ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql | 0 .../ExternalAPIs/UntrustedDataToExternalAPI.qhelp | 0 .../{POI => Security}/ExternalAPIs/UntrustedDataToExternalAPI.ql | 0 .../POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref | 1 - .../POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref | 1 - .../ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected | 0 .../ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref | 1 + .../ExternalAPIs/UntrustedDataToExternalAPI.expected | 0 .../Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref | 1 + .../ql/test/query-tests/{POI => Security}/ExternalAPIs/test.py | 0 14 files changed, 2 insertions(+), 2 deletions(-) rename python/ql/src/{POI => Security}/ExternalAPIs/ExternalAPISinkExample.py (100%) rename python/ql/src/{POI => Security}/ExternalAPIs/ExternalAPITaintStepExample.py (100%) rename python/ql/src/{POI => Security}/ExternalAPIs/ExternalAPIs.qll (100%) rename python/ql/src/{POI => Security}/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp (100%) rename python/ql/src/{POI => Security}/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql (100%) rename python/ql/src/{POI => Security}/ExternalAPIs/UntrustedDataToExternalAPI.qhelp (100%) rename python/ql/src/{POI => Security}/ExternalAPIs/UntrustedDataToExternalAPI.ql (100%) delete mode 100644 python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref delete mode 100644 python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref rename python/ql/test/query-tests/{POI => Security}/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected (100%) create mode 100644 python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref rename python/ql/test/query-tests/{POI => Security}/ExternalAPIs/UntrustedDataToExternalAPI.expected (100%) create mode 100644 python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref rename python/ql/test/query-tests/{POI => Security}/ExternalAPIs/test.py (100%) diff --git a/python/ql/src/POI/ExternalAPIs/ExternalAPISinkExample.py b/python/ql/src/Security/ExternalAPIs/ExternalAPISinkExample.py similarity index 100% rename from python/ql/src/POI/ExternalAPIs/ExternalAPISinkExample.py rename to python/ql/src/Security/ExternalAPIs/ExternalAPISinkExample.py diff --git a/python/ql/src/POI/ExternalAPIs/ExternalAPITaintStepExample.py b/python/ql/src/Security/ExternalAPIs/ExternalAPITaintStepExample.py similarity index 100% rename from python/ql/src/POI/ExternalAPIs/ExternalAPITaintStepExample.py rename to python/ql/src/Security/ExternalAPIs/ExternalAPITaintStepExample.py diff --git a/python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/ExternalAPIs/ExternalAPIs.qll similarity index 100% rename from python/ql/src/POI/ExternalAPIs/ExternalAPIs.qll rename to python/ql/src/Security/ExternalAPIs/ExternalAPIs.qll diff --git a/python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp b/python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp similarity index 100% rename from python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp rename to python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp diff --git a/python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql b/python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql similarity index 100% rename from python/ql/src/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql rename to python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.qhelp b/python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.qhelp similarity index 100% rename from python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.qhelp rename to python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.qhelp diff --git a/python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.ql b/python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.ql similarity index 100% rename from python/ql/src/POI/ExternalAPIs/UntrustedDataToExternalAPI.ql rename to python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref b/python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref deleted file mode 100644 index af8f30055eb..00000000000 --- a/python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref +++ /dev/null @@ -1 +0,0 @@ -POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref deleted file mode 100644 index 91c47f14b1c..00000000000 --- a/python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.qlref +++ /dev/null @@ -1 +0,0 @@ -POI/ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected similarity index 100% rename from python/ql/test/query-tests/POI/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected rename to python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref b/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref new file mode 100644 index 00000000000..1968cf40cb8 --- /dev/null +++ b/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref @@ -0,0 +1 @@ +Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.expected similarity index 100% rename from python/ql/test/query-tests/POI/ExternalAPIs/UntrustedDataToExternalAPI.expected rename to python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.expected diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref new file mode 100644 index 00000000000..bdbdbdb3ec7 --- /dev/null +++ b/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref @@ -0,0 +1 @@ +Security/ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/test/query-tests/POI/ExternalAPIs/test.py b/python/ql/test/query-tests/Security/ExternalAPIs/test.py similarity index 100% rename from python/ql/test/query-tests/POI/ExternalAPIs/test.py rename to python/ql/test/query-tests/Security/ExternalAPIs/test.py From c07a60818c9f9af91496d12ff221940b971f0662 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 17 Feb 2021 10:49:28 +0000 Subject: [PATCH 421/429] C++: Simplify IteratorAssignArithmeticOperator. --- .../src/semmle/code/cpp/models/implementations/Iterator.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll index e8ad3d454d8..24d5456293f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Iterator.qll @@ -157,11 +157,9 @@ private class IteratorSubOperator extends Operator, TaintFunction { * A non-member `operator+=` or `operator-=` function for an iterator type. */ private class IteratorAssignArithmeticOperator extends Operator, DataFlowFunction, TaintFunction { - FunctionInput iteratorInput; - IteratorAssignArithmeticOperator() { this.hasName(["operator+=", "operator-="]) and - iteratorInput = getIteratorArgumentInput(this, 0) + exists(getIteratorArgumentInput(this, 0)) } override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { From 25beadcb0591ef119efee3720ac9a79412804678 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 17 Feb 2021 11:54:24 +0100 Subject: [PATCH 422/429] Update cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com> --- .../query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c index fd24379b890..77c830985d2 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-079/semmle/CgiXss/search.c @@ -37,7 +37,7 @@ void good_server1(char* query) { puts(do_search(query)); } -int scanf(const char *, ...); +int sscanf(const char *s, const char *format, ...); void good_server2(char* query) { puts("

    Query results for "); @@ -59,4 +59,3 @@ int main(int argc, char** argv) { good_server2(raw_query); } } - From a03507a544b8d2ecffa1344a5a5a3867ef62c403 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Feb 2021 13:12:35 +0100 Subject: [PATCH 423/429] avoid cartesian product in isFilteredPropertyName --- .../dataflow/CleartextLoggingCustomizations.qll | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll index 78a26eb4228..b0b9632a63c 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/CleartextLoggingCustomizations.qll @@ -221,20 +221,16 @@ module CleartextLogging { /** * Holds if `name` is filtered by e.g. a regular-expression test or a filter call. */ - private predicate isFilteredPropertyName(DataFlow::Node name) { + private predicate isFilteredPropertyName(DataFlow::SourceNode name) { exists(DataFlow::MethodCallNode reduceCall | - reduceCall.getABoundCallbackParameter(0, 1).flowsTo(name) and - reduceCall.getMethodName() = "reduce" + reduceCall.getMethodName() = "reduce" and + reduceCall.getABoundCallbackParameter(0, 1) = name | reduceCall.getReceiver+().(DataFlow::MethodCallNode).getMethodName() = "filter" ) or - exists(StringOps::RegExpTest test | - test.getStringOperand().getALocalSource() = name.getALocalSource() - ) + exists(StringOps::RegExpTest test | test.getStringOperand().getALocalSource() = name) or - exists(MembershipCandidate test | - test.getAMemberNode().getALocalSource() = name.getALocalSource() - ) + exists(MembershipCandidate test | test.getAMemberNode().getALocalSource() = name) } } From a4de88d39c6370cec253966826d7d08ec66c859f Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 13:11:40 +0100 Subject: [PATCH 424/429] Python: Update type-tracking snippet based on what I learned in https://github.com/github/codeql/pull/5184 --- python/.vscode/ql.code-snippets | 8 ++++---- python/ql/src/semmle/python/dataflow/new/TypeTracker.qll | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/.vscode/ql.code-snippets b/python/.vscode/ql.code-snippets index 80c6ef1290d..6ccb9aa6657 100644 --- a/python/.vscode/ql.code-snippets +++ b/python/.vscode/ql.code-snippets @@ -105,8 +105,8 @@ "scope": "ql", "prefix": "type tracking", "body": [ - "/** Gets a reference to a ${3:thing}. */", - "private DataFlow::Node ${1:myType}(DataFlow::TypeTracker t) {", + "/** Gets a reference to ${3:a thing}. */", + "private DataFlow::LocalSourceNode ${1:myType}(DataFlow::TypeTracker t) {", " t.start() and", " result = ${2:value}", " or", @@ -115,9 +115,9 @@ " )", "}", "", - "/** Gets a reference to a ${3:thing}. */", + "/** Gets a reference to $3. */", "DataFlow::Node $1() {", - " result = $1(DataFlow::TypeTracker::end())", + " $1(DataFlow::TypeTracker::end()).flowsTo(result)", "}" ], "description": "Type tracking predicate", diff --git a/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll b/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll index b6de3cd7764..be9b42d470e 100644 --- a/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll +++ b/python/ql/src/semmle/python/dataflow/new/TypeTracker.qll @@ -180,7 +180,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalAttributeN * It is recommended that all uses of this type are written in the following form, * for tracking some type `myType`: * ``` - * DataFlow::Node myType(DataFlow::TypeTracker t) { + * DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) { * t.start() and * result = < source of myType > * or @@ -189,7 +189,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalAttributeN * ) * } * - * DataFlow::Node myType() { result = myType(DataFlow::TypeTracker::end()) } + * DataFlow::Node myType() { myType(DataFlow::TypeTracker::end()).flowsTo(result) } * ``` * * Instead of `result = myType(t2).track(t2, t)`, you can also use the equivalent From 0cdb5c48cfed8556c556c7009cabde2b21bde08c Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 13:14:23 +0100 Subject: [PATCH 425/429] Python: Remove type-tracking snippets for framework modeling We won't need these anymore, since we can now use API graphs --- python/.vscode/ql.code-snippets | 200 -------------------------------- 1 file changed, 200 deletions(-) diff --git a/python/.vscode/ql.code-snippets b/python/.vscode/ql.code-snippets index 6ccb9aa6657..59f230193b0 100644 --- a/python/.vscode/ql.code-snippets +++ b/python/.vscode/ql.code-snippets @@ -123,92 +123,6 @@ "description": "Type tracking predicate", }, - "Type tracking module": { - "scope": "ql", - "prefix": "type tracking module", - "body": [ - "// ---------------------------------------------------------------------------", - "// ${1:modulename}", - "// ---------------------------------------------------------------------------", - "/** Gets a reference to the `$1` module. */", - "private DataFlow::Node $1(DataFlow::TypeTracker t) {", - " t.start() and", - " result = DataFlow::importNode(\"$1\")", - " or", - " exists(DataFlow::TypeTracker t2 | result = $1(t2).track(t2, t))", - "}", - "", - "/** Gets a reference to the `$1` module. */", - "DataFlow::Node $1() { result = $1(DataFlow::TypeTracker::end()) }", - "", - "/**", - " * Gets a reference to the attribute `attr_name` of the `$1` module.", - " * WARNING: Only holds for a few predefined attributes.", - " */", - "private DataFlow::Node $1_attr(DataFlow::TypeTracker t, string attr_name) {", - " attr_name in [\"${2:name}\"] and", - " (", - " t.start() and", - " result = DataFlow::importNode(\"$1\" + \".\" + attr_name)", - " or", - " t.startInAttr(attr_name) and", - " result = $1()", - " )", - " or", - " // Due to bad performance when using normal setup with `$1_attr(t2, attr_name).track(t2, t)`", - " // we have inlined that code and forced a join", - " exists(DataFlow::TypeTracker t2 |", - " exists(DataFlow::StepSummary summary |", - " $1_attr_first_join(t2, attr_name, result, summary) and", - " t = t2.append(summary)", - " )", - " )", - "}", - "", - "pragma[nomagic]", - "private predicate $1_attr_first_join(", - " DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res, DataFlow::StepSummary summary", - ") {", - " DataFlow::StepSummary::step($1_attr(t2, attr_name), res, summary)", - "}", - "", - "/**", - " * Gets a reference to the attribute `attr_name` of the `$1` module.", - " * WARNING: Only holds for a few predefined attributes.", - " */", - "private DataFlow::Node $1_attr(string attr_name) {", - " result = $1_attr(DataFlow::TypeTracker::end(), attr_name)", - "}", - "", - "/** Provides models for the `$1` module. */", - "module $1 {", - "", - "}", - ], - "description": "Type tracking module", - }, - - "Type tracking module member": { - "scope": "ql", - "prefix": "type tracking module member", - "body": [ - "/** Gets a reference to the `${1:module}.${2:member}` ${3:object/class}. */", - "private DataFlow::Node ${4:$2}(DataFlow::TypeTracker t) {", - " t.start() and", - " result = DataFlow::importNode(\"$1.$2\")", - " or", - " t.startInAttr(\"$2\") and", - " result = $1()", - " or", - " exists(DataFlow::TypeTracker t2 | result = $4(t2).track(t2, t))", - "}", - " ", - "/** Gets a reference to the `$1.$2` $3. */", - "DataFlow::Node $4() { result = $4(DataFlow::TypeTracker::end()) }", - ], - "description": "Type tracking module member", - }, - "Taint tracking configuration": { "scope": "ql", "prefix": "taint tracking", @@ -238,118 +152,4 @@ ] }, - "Type tracking submodule": { - "scope": "ql", - "prefix": "type tracking submodule", - "body": [ - " // -------------------------------------------------------------------------", - " // ${1:parent}.${2:submodule}", - " // -------------------------------------------------------------------------", - " /** Gets a reference to the `$1.$2` module. */", - " DataFlow::Node $2() { result = $1_attr(\"$2\") }", - "", - " /** Provides models for the `$1.$2` module */", - " module $2 {", - " /**", - " * Gets a reference to the attribute `attr_name` of the `$1.$2` module.", - " * WARNING: Only holds for a few predefined attributes.", - " */", - " private DataFlow::Node $2_attr(DataFlow::TypeTracker t, string attr_name) {", - " attr_name in [\"$3\"] and", - " (", - " t.start() and", - " result = DataFlow::importNode(\"$1.$2\" + \".\" + attr_name)", - " or", - " t.startInAttr(attr_name) and", - " result = $2()", - " )", - " or", - " // Due to bad performance when using normal setup with `$2_attr(t2, attr_name).track(t2, t)`", - " // we have inlined that code and forced a join", - " exists(DataFlow::TypeTracker t2 |", - " exists(DataFlow::StepSummary summary |", - " $2_attr_first_join(t2, attr_name, result, summary) and", - " t = t2.append(summary)", - " )", - " )", - " }", - "", - " pragma[nomagic]", - " private predicate $2_attr_first_join(", - " DataFlow::TypeTracker t2, string attr_name, DataFlow::Node res,", - " DataFlow::StepSummary summary", - " ) {", - " DataFlow::StepSummary::step($2_attr(t2, attr_name), res, summary)", - " }", - "", - " /**", - " * Gets a reference to the attribute `attr_name` of the `$1.$2` module.", - " * WARNING: Only holds for a few predefined attributes.", - " */", - " private DataFlow::Node $2_attr(string attr_name) {", - " result = $2_attr(DataFlow::TypeTracker::end(), attr_name)", - " }", - " }", - ], - "description": "Type tracking submodule", - }, - - "Type tracking class": { - "scope": "ql", - "prefix": "type tracking class", - "body": [ - " /**", - " * Provides models for the `${1:module}.${2:classname}` class", - " *", - " * See ${6:apiref}.", - " */", - " module $2 {", - " /** Gets a reference to the `$1.$2` class. */", - " private DataFlow::Node classRef(DataFlow::TypeTracker t) {", - " t.start() and", - " result = ${4:module}_attr(\"$2\")", - " or", - " // TODO: remove/expand this part of the template as needed", - " // Handle `${5:toplevel}.$2` alias", - " t.start() and", - " result = $5_attr(\"$2\")", - " or", - " exists(DataFlow::TypeTracker t2 | result = classRef(t2).track(t2, t))", - " }", - "", - " /** Gets a reference to the `$1.$2` class. */", - " DataFlow::Node classRef() { result = classRef(DataFlow::TypeTracker::end()) }", - "", - " /**", - " * A source of instances of `$1.$2`, extend this class to model new instances.", - " *", - " * This can include instantiations of the class, return values from function", - " * calls, or a special parameter that will be set when functions are called by an external", - " * library.", - " *", - " * Use the predicate `$2::instance()` to get references to instances of `$1.$2`.", - " */", - " abstract class InstanceSource extends DataFlow::Node { }", - "", - " /** A direct instantiation of `$1.$2`. */", - " private class ClassInstantiation extends InstanceSource, DataFlow::CfgNode {", - " override CallNode node;", - "", - " ClassInstantiation() { node.getFunction() = classRef().asCfgNode() }", - " }", - "", - " /** Gets a reference to an instance of `$1.$2`. */", - " private DataFlow::Node instance(DataFlow::TypeTracker t) {", - " t.start() and", - " result instanceof InstanceSource", - " or", - " exists(DataFlow::TypeTracker t2 | result = instance(t2).track(t2, t))", - " }", - "", - " /** Gets a reference to an instance of `$1.$2`. */", - " DataFlow::Node instance() { result = instance(DataFlow::TypeTracker::end()) }", - " }", - ], - "description": "Type tracking class", - }, } From 7afe3972d821de0c96d933a21642baa560597261 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 16:32:53 +0100 Subject: [PATCH 426/429] Revert "Merge pull request #5171 from RasmusWL/restructure-queries" This reverts commit 8caafb3710cda146544b28d17523e81d9f6249b6, reversing changes made to ec79094957aed4ccc6b8c21ee01b58c90198c013. --- .../BindToAllInterfaces.py | 0 .../BindToAllInterfaces.qhelp | 0 .../BindToAllInterfaces.ql | 0 .../ExternalAPISinkExample.py | 0 .../ExternalAPITaintStepExample.py | 0 .../{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPIs.qll | 1 - .../ExternalAPIsUsedWithUntrustedData.qhelp | 0 .../ExternalAPIsUsedWithUntrustedData.ql | 0 .../UntrustedDataToExternalAPI.qhelp | 0 .../UntrustedDataToExternalAPI.ql | 0 .../IncompleteHostnameRegExp.qhelp | 0 .../IncompleteHostnameRegExp.ql | 0 .../IncompleteUrlSubstringSanitization.qhelp | 0 .../IncompleteUrlSubstringSanitization.ql | 0 .../examples/IncompleteHostnameRegExp.py | 0 .../examples/IncompleteUrlSubstringSanitization.py | 0 .../{Injection/PathInjection => CWE-022}/PathInjection.qhelp | 0 .../{Injection/PathInjection => CWE-022}/PathInjection.ql | 0 .../src/Security/{Injection/TarSlip => CWE-022}/TarSlip.qhelp | 0 .../ql/src/Security/{Injection/TarSlip => CWE-022}/TarSlip.ql | 0 .../PathInjection => CWE-022}/examples/tainted_path.py | 0 .../{Injection/TarSlip => CWE-022}/examples/tarslip_bad.py | 0 .../{Injection/TarSlip => CWE-022}/examples/tarslip_good.py | 0 .../CommandInjection => CWE-078}/CommandInjection.qhelp | 0 .../{Injection/CommandInjection => CWE-078}/CommandInjection.ql | 0 .../CommandInjection => CWE-078}/examples/command_injection.py | 0 .../Jinja2WithoutEscaping.qhelp | 0 .../Jinja2WithoutEscaping.ql | 0 .../{Injection/ReflectedXss => CWE-079}/ReflectedXss.qhelp | 0 .../{Injection/ReflectedXss => CWE-079}/ReflectedXss.ql | 0 .../Jinja2RenderWithoutEscape => CWE-079}/examples/jinja2.py | 0 .../{Injection/ReflectedXss => CWE-079}/examples/xss.py | 0 .../{Injection/SqlInjection => CWE-089}/SqlInjection.qhelp | 0 .../{Injection/SqlInjection => CWE-089}/SqlInjection.ql | 0 .../SqlInjection => CWE-089}/examples/sql_injection.py | 0 .../{Injection/CodeInjection => CWE-094}/CodeInjection.qhelp | 0 .../{Injection/CodeInjection => CWE-094}/CodeInjection.ql | 0 .../CodeInjection => CWE-094}/examples/code_injection.py | 0 .../StackTraceExposure => CWE-209}/StackTraceExposure.py | 0 .../StackTraceExposure => CWE-209}/StackTraceExposure.qhelp | 0 .../StackTraceExposure => CWE-209}/StackTraceExposure.ql | 0 .../{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.py | 0 .../{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.qhelp | 0 .../{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.ql | 0 .../MissingHostKeyValidation.qhelp} | 0 .../MissingHostKeyValidation.ql} | 0 .../RequestWithoutValidation.qhelp} | 0 .../RequestWithoutValidation.ql} | 0 .../examples/make_request.py | 0 .../examples/paramiko_host_key.py | 0 .../SensitiveDataExposure => CWE-312}/CleartextLogging.qhelp | 0 .../SensitiveDataExposure => CWE-312}/CleartextLogging.ql | 0 .../SensitiveDataExposure => CWE-312}/CleartextStorage.qhelp | 0 .../SensitiveDataExposure => CWE-312}/CleartextStorage.ql | 0 .../examples/password_in_cookie.py | 0 .../WeakCryptoKey.qhelp => CWE-326/WeakCrypto.qhelp} | 0 .../WeakCryptoKey/WeakCryptoKey.ql => CWE-326/WeakCrypto.ql} | 0 .../BrokenCryptoAlgorithm.qhelp} | 2 +- .../WeakCryptoAlgorithm.ql => CWE-327/BrokenCryptoAlgorithm.ql} | 0 .../{Crypto/TLS => CWE-327}/InsecureDefaultProtocol.qhelp | 0 .../Security/{Crypto/TLS => CWE-327}/InsecureDefaultProtocol.ql | 0 .../src/Security/{Crypto/TLS => CWE-327}/InsecureProtocol.qhelp | 0 .../ql/src/Security/{Crypto/TLS => CWE-327}/InsecureProtocol.ql | 0 .../examples/broken_crypto.py} | 0 .../TLS => CWE-327}/examples/insecure_default_protocol.py | 0 .../{Crypto/TLS => CWE-327}/examples/insecure_protocol.py | 0 .../InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.py | 0 .../InsecureTemporaryFile.qhelp | 0 .../InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.ql | 0 .../InsecureTemporaryFile => CWE-377}/SecureTemporaryFile.py | 0 .../{Injection/UnsafeDeserialization => CWE-502}/JsonGood.py | 0 .../UnsafeDeserialization => CWE-502}/UnpicklingBad.py | 0 .../UnsafeDeserialization.qhelp | 0 .../UnsafeDeserialization => CWE-502}/UnsafeDeserialization.ql | 0 .../OpenRedirect.qhelp => CWE-601/UrlRedirect.qhelp} | 0 .../OpenRedirect/OpenRedirect.ql => CWE-601/UrlRedirect.ql} | 0 .../OpenRedirect => CWE-601}/examples/redirect_bad.py | 0 .../OpenRedirect => CWE-601}/examples/redirect_good.py | 0 .../WeakFilePermissions => CWE-732}/WeakFilePermissions.qhelp | 0 .../WeakFilePermissions => CWE-732}/WeakFilePermissions.ql | 0 .../HardcodedCredentials => CWE-798}/HardcodedCredentials.py | 0 .../HardcodedCredentials => CWE-798}/HardcodedCredentials.qhelp | 0 .../HardcodedCredentials => CWE-798}/HardcodedCredentials.ql | 0 .../BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref | 1 - .../Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref | 1 - .../query-tests/Security/BadPractice/FlaskRunWithDebug/options | 1 - .../RequestWithoutValidation.qlref | 1 - .../BadPractice/HTTPSRequestWithoutCertValidation/options | 1 - .../BadPractice/HardcodedCredentials/HardcodedCredentials.qlref | 1 - .../IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref | 1 - .../IncompleteUrlSubstringSanitization.qlref | 1 - .../InsecureTemporaryFile/InsecureTemporaryFile.qlref | 1 - .../Security/BadPractice/InsecureTemporaryFile/options | 1 - .../Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref | 1 - .../SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref | 1 - .../Security/BadPractice/SSHMissingHostKeyValidation/options | 1 - .../BadPractice/WeakFilePermissions/WeakFilePermissions.qlref | 1 - .../Security/BadPractice/WeakFilePermissions/options | 1 - .../BindToAllInterfaces.expected | 0 .../Security/CVE-2018-1281/BindToAllInterfaces.qlref | 1 + .../BindToAllInterfaces_test.py | 0 .../{BadPractice/BindToAllInterfaces => CVE-2018-1281}/options | 0 .../ExternalAPIsUsedWithUntrustedData.expected | 0 .../ExternalAPIsUsedWithUntrustedData.qlref | 1 + .../UntrustedDataToExternalAPI.expected | 0 .../CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref | 1 + .../Security/{ExternalAPIs => CWE-020-ExternalAPIs}/test.py | 0 .../IncompleteHostnameRegExp.expected | 0 .../query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref | 1 + .../IncompleteUrlSubstringSanitization.expected | 0 .../Security/CWE-020/IncompleteUrlSubstringSanitization.qlref | 1 + .../{BadPractice/IncompleteUrlSanitizer => CWE-020}/hosttest.py | 0 .../{BadPractice/IncompleteUrlSanitizer => CWE-020}/urltest.py | 0 .../PathInjection.expected | 0 .../Security/CWE-022-PathInjection/PathInjection.qlref | 1 + .../PathInjection => CWE-022-PathInjection}/path_injection.py | 0 .../{Injection/PathInjection => CWE-022-PathInjection}/test.py | 0 .../PathInjection => CWE-022-PathInjection}/test_chaining.py | 0 .../{Injection/TarSlip => CWE-022-TarSlip}/TarSlip.expected | 0 .../ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref | 1 + .../Jinja2RenderWithoutEscape => CWE-022-TarSlip}/options | 0 .../Security/{Injection/TarSlip => CWE-022-TarSlip}/tarslip.py | 0 .../CommandInjection.expected | 0 .../query-tests/Security/CWE-078-py2/CommandInjection.qlref | 1 + .../CommandInjection-py2 => CWE-078-py2}/command_injection.py | 0 .../{Injection/CommandInjection-py2 => CWE-078-py2}/options | 0 .../CommandInjection => CWE-078}/CommandInjection.expected | 0 .../ql/test/query-tests/Security/CWE-078/CommandInjection.qlref | 1 + .../CommandInjection => CWE-078}/command_injection.py | 0 .../Security/{Injection/CommandInjection => CWE-078}/options | 0 .../Jinja2WithoutEscaping.expected | 0 .../query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref | 1 + .../{Injection/ReflectedXss => CWE-079}/ReflectedXss.expected | 0 python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref | 1 + .../Jinja2RenderWithoutEscape => CWE-079}/jinja2_escaping.py | 0 python/ql/test/query-tests/Security/CWE-079/options | 1 + .../{Injection/ReflectedXss => CWE-079}/reflected_xss.py | 0 .../{Injection/SqlInjection => CWE-089}/SqlInjection.expected | 0 python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref | 1 + .../{Injection/SqlInjection => CWE-089}/sql_injection.py | 0 .../{Injection/CodeInjection => CWE-094}/CodeInjection.expected | 0 python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref | 1 + .../{Injection/CodeInjection => CWE-094}/code_injection.py | 0 .../StackTraceExposure => CWE-209}/StackTraceExposure.expected | 0 .../test/query-tests/Security/CWE-209/StackTraceExposure.qlref | 1 + python/ql/test/query-tests/Security/CWE-209/options | 1 + .../Security/{Exposure/StackTraceExposure => CWE-209}/test.py | 0 .../FlaskRunWithDebug => CWE-215}/FlaskDebug.expected | 0 python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref | 1 + python/ql/test/query-tests/Security/CWE-215/options | 1 + .../Security/{BadPractice/FlaskRunWithDebug => CWE-215}/test.py | 0 .../MissingHostKeyValidation.expected | 0 .../query-tests/Security/CWE-295/MissingHostKeyValidation.qlref | 1 + .../RequestWithoutValidation.expected | 0 .../query-tests/Security/CWE-295/RequestWithoutValidation.qlref | 1 + .../make_request.py | 0 python/ql/test/query-tests/Security/CWE-295/options | 1 + .../paramiko_host_key.py | 0 .../SensitiveDataExposure => CWE-312}/CleartextLogging.expected | 0 .../ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref | 1 + .../SensitiveDataExposure => CWE-312}/CleartextStorage.expected | 0 .../ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref | 1 + python/ql/test/query-tests/Security/CWE-312/options | 1 + .../SensitiveDataExposure => CWE-312}/password_in_cookie.py | 0 .../{Exposure/SensitiveDataExposure => CWE-312}/test.py | 0 .../{Crypto/WeakCryptoKey => CWE-326}/WeakCrypto.expected | 0 python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref | 1 + python/ql/test/query-tests/Security/CWE-326/options | 1 + .../Security/{Crypto/WeakCryptoKey => CWE-326}/weak_crypto.py | 0 .../BrokenCryptoAlgorithm.expected | 0 .../query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref | 1 + .../{Crypto/TLS => CWE-327}/InsecureDefaultProtocol.expected | 0 .../query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref | 1 + .../Security/{Crypto/TLS => CWE-327}/InsecureProtocol.expected | 0 .../Security/{Crypto/TLS => CWE-327}/InsecureProtocol.py | 0 .../ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref | 1 + .../{Crypto/WeakCryptoAlgorithm => CWE-327}/TestNode.expected | 0 .../{Crypto/WeakCryptoAlgorithm => CWE-327}/TestNode.ql | 0 python/ql/test/query-tests/Security/CWE-327/options | 1 + .../WeakCryptoAlgorithm => CWE-327}/test_cryptography.py | 0 .../{Crypto/WeakCryptoAlgorithm => CWE-327}/test_pycrypto.py | 0 .../InsecureTemporaryFile.expected | 0 .../InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.py | 0 .../query-tests/Security/CWE-377/InsecureTemporaryFile.qlref | 1 + .../InsecureTemporaryFile => CWE-377}/SecureTemporaryFile.py | 0 python/ql/test/query-tests/Security/CWE-377/options | 1 + .../UnsafeDeserialization.expected | 0 .../query-tests/Security/CWE-502/UnsafeDeserialization.qlref | 1 + .../UnsafeDeserialization => CWE-502}/unsafe_deserialization.py | 0 .../{Injection/OpenRedirect => CWE-601}/UrlRedirect.expected | 0 python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref | 2 ++ python/ql/test/query-tests/Security/CWE-601/options | 1 + .../Security/{Injection/OpenRedirect => CWE-601}/test.py | 0 .../WeakFilePermissions.expected | 0 .../test/query-tests/Security/CWE-732/WeakFilePermissions.qlref | 1 + python/ql/test/query-tests/Security/CWE-732/options | 1 + .../{BadPractice/WeakFilePermissions => CWE-732}/test.py | 0 .../HardcodedCredentials.expected | 0 .../query-tests/Security/CWE-798/HardcodedCredentials.qlref | 1 + .../{BadPractice/HardcodedCredentials => CWE-798}/test.py | 0 .../Security/Crypto/TLS/InsecureDefaultProtocol.qlref | 1 - .../test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref | 1 - python/ql/test/query-tests/Security/Crypto/TLS/options | 1 - .../Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref | 1 - .../query-tests/Security/Crypto/WeakCryptoAlgorithm/options | 1 - .../query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref | 1 - .../ql/test/query-tests/Security/Crypto/WeakCryptoKey/options | 1 - .../Exposure/SensitiveDataExposure/CleartextLogging.qlref | 1 - .../Exposure/SensitiveDataExposure/CleartextStorage.qlref | 1 - .../query-tests/Security/Exposure/SensitiveDataExposure/options | 1 - .../Exposure/StackTraceExposure/StackTraceExposure.qlref | 1 - .../query-tests/Security/Exposure/StackTraceExposure/options | 1 - .../ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref | 1 - .../Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref | 1 - .../Security/Injection/CodeInjection/CodeInjection.qlref | 1 - .../Injection/CommandInjection-py2/CommandInjection.qlref | 1 - .../Security/Injection/CommandInjection/CommandInjection.qlref | 1 - .../Security/Injection/OpenRedirect/UrlRedirect.qlref | 1 - .../ql/test/query-tests/Security/Injection/OpenRedirect/options | 1 - .../Security/Injection/PathInjection/PathInjection.qlref | 1 - .../Security/Injection/ReflectedXss/ReflectedXss.qlref | 1 - .../Security/Injection/SqlInjection/SqlInjection.qlref | 1 - .../test/query-tests/Security/Injection/TarSlip/TarSlip.qlref | 1 - python/ql/test/query-tests/Security/Injection/TarSlip/options | 1 - .../Injection/UnsafeDeserialization/UnsafeDeserialization.qlref | 1 - 225 files changed, 40 insertions(+), 42 deletions(-) rename python/ql/src/Security/{BadPractice/BindToAllInterfaces => CVE-2018-1281}/BindToAllInterfaces.py (100%) rename python/ql/src/Security/{BadPractice/BindToAllInterfaces => CVE-2018-1281}/BindToAllInterfaces.qhelp (100%) rename python/ql/src/Security/{BadPractice/BindToAllInterfaces => CVE-2018-1281}/BindToAllInterfaces.ql (100%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPISinkExample.py (100%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPITaintStepExample.py (100%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPIs.qll (98%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.qhelp (100%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.ql (100%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/UntrustedDataToExternalAPI.qhelp (100%) rename python/ql/src/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/UntrustedDataToExternalAPI.ql (100%) rename python/ql/src/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/IncompleteHostnameRegExp.qhelp (100%) rename python/ql/src/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/IncompleteHostnameRegExp.ql (100%) rename python/ql/src/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/IncompleteUrlSubstringSanitization.qhelp (100%) rename python/ql/src/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/IncompleteUrlSubstringSanitization.ql (100%) rename python/ql/src/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/examples/IncompleteHostnameRegExp.py (100%) rename python/ql/src/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/examples/IncompleteUrlSubstringSanitization.py (100%) rename python/ql/src/Security/{Injection/PathInjection => CWE-022}/PathInjection.qhelp (100%) rename python/ql/src/Security/{Injection/PathInjection => CWE-022}/PathInjection.ql (100%) rename python/ql/src/Security/{Injection/TarSlip => CWE-022}/TarSlip.qhelp (100%) rename python/ql/src/Security/{Injection/TarSlip => CWE-022}/TarSlip.ql (100%) rename python/ql/src/Security/{Injection/PathInjection => CWE-022}/examples/tainted_path.py (100%) rename python/ql/src/Security/{Injection/TarSlip => CWE-022}/examples/tarslip_bad.py (100%) rename python/ql/src/Security/{Injection/TarSlip => CWE-022}/examples/tarslip_good.py (100%) rename python/ql/src/Security/{Injection/CommandInjection => CWE-078}/CommandInjection.qhelp (100%) rename python/ql/src/Security/{Injection/CommandInjection => CWE-078}/CommandInjection.ql (100%) rename python/ql/src/Security/{Injection/CommandInjection => CWE-078}/examples/command_injection.py (100%) rename python/ql/src/Security/{BadPractice/Jinja2RenderWithoutEscape => CWE-079}/Jinja2WithoutEscaping.qhelp (100%) rename python/ql/src/Security/{BadPractice/Jinja2RenderWithoutEscape => CWE-079}/Jinja2WithoutEscaping.ql (100%) rename python/ql/src/Security/{Injection/ReflectedXss => CWE-079}/ReflectedXss.qhelp (100%) rename python/ql/src/Security/{Injection/ReflectedXss => CWE-079}/ReflectedXss.ql (100%) rename python/ql/src/Security/{BadPractice/Jinja2RenderWithoutEscape => CWE-079}/examples/jinja2.py (100%) rename python/ql/src/Security/{Injection/ReflectedXss => CWE-079}/examples/xss.py (100%) rename python/ql/src/Security/{Injection/SqlInjection => CWE-089}/SqlInjection.qhelp (100%) rename python/ql/src/Security/{Injection/SqlInjection => CWE-089}/SqlInjection.ql (100%) rename python/ql/src/Security/{Injection/SqlInjection => CWE-089}/examples/sql_injection.py (100%) rename python/ql/src/Security/{Injection/CodeInjection => CWE-094}/CodeInjection.qhelp (100%) rename python/ql/src/Security/{Injection/CodeInjection => CWE-094}/CodeInjection.ql (100%) rename python/ql/src/Security/{Injection/CodeInjection => CWE-094}/examples/code_injection.py (100%) rename python/ql/src/Security/{Exposure/StackTraceExposure => CWE-209}/StackTraceExposure.py (100%) rename python/ql/src/Security/{Exposure/StackTraceExposure => CWE-209}/StackTraceExposure.qhelp (100%) rename python/ql/src/Security/{Exposure/StackTraceExposure => CWE-209}/StackTraceExposure.ql (100%) rename python/ql/src/Security/{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.py (100%) rename python/ql/src/Security/{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.qhelp (100%) rename python/ql/src/Security/{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.ql (100%) rename python/ql/src/Security/{BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.qhelp => CWE-295/MissingHostKeyValidation.qhelp} (100%) rename python/ql/src/Security/{BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql => CWE-295/MissingHostKeyValidation.ql} (100%) rename python/ql/src/Security/{BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.qhelp => CWE-295/RequestWithoutValidation.qhelp} (100%) rename python/ql/src/Security/{BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql => CWE-295/RequestWithoutValidation.ql} (100%) rename python/ql/src/Security/{BadPractice/HTTPSRequestWithoutCertValidation => CWE-295}/examples/make_request.py (100%) rename python/ql/src/Security/{BadPractice/SSHMissingHostKeyValidation => CWE-295}/examples/paramiko_host_key.py (100%) rename python/ql/src/Security/{Exposure/SensitiveDataExposure => CWE-312}/CleartextLogging.qhelp (100%) rename python/ql/src/Security/{Exposure/SensitiveDataExposure => CWE-312}/CleartextLogging.ql (100%) rename python/ql/src/Security/{Exposure/SensitiveDataExposure => CWE-312}/CleartextStorage.qhelp (100%) rename python/ql/src/Security/{Exposure/SensitiveDataExposure => CWE-312}/CleartextStorage.ql (100%) rename python/ql/src/Security/{Exposure/SensitiveDataExposure => CWE-312}/examples/password_in_cookie.py (100%) rename python/ql/src/Security/{Crypto/WeakCryptoKey/WeakCryptoKey.qhelp => CWE-326/WeakCrypto.qhelp} (100%) rename python/ql/src/Security/{Crypto/WeakCryptoKey/WeakCryptoKey.ql => CWE-326/WeakCrypto.ql} (100%) rename python/ql/src/Security/{Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp => CWE-327/BrokenCryptoAlgorithm.qhelp} (97%) rename python/ql/src/Security/{Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql => CWE-327/BrokenCryptoAlgorithm.ql} (100%) rename python/ql/src/Security/{Crypto/TLS => CWE-327}/InsecureDefaultProtocol.qhelp (100%) rename python/ql/src/Security/{Crypto/TLS => CWE-327}/InsecureDefaultProtocol.ql (100%) rename python/ql/src/Security/{Crypto/TLS => CWE-327}/InsecureProtocol.qhelp (100%) rename python/ql/src/Security/{Crypto/TLS => CWE-327}/InsecureProtocol.ql (100%) rename python/ql/src/Security/{Crypto/WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py => CWE-327/examples/broken_crypto.py} (100%) rename python/ql/src/Security/{Crypto/TLS => CWE-327}/examples/insecure_default_protocol.py (100%) rename python/ql/src/Security/{Crypto/TLS => CWE-327}/examples/insecure_protocol.py (100%) rename python/ql/src/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.py (100%) rename python/ql/src/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.qhelp (100%) rename python/ql/src/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.ql (100%) rename python/ql/src/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/SecureTemporaryFile.py (100%) rename python/ql/src/Security/{Injection/UnsafeDeserialization => CWE-502}/JsonGood.py (100%) rename python/ql/src/Security/{Injection/UnsafeDeserialization => CWE-502}/UnpicklingBad.py (100%) rename python/ql/src/Security/{Injection/UnsafeDeserialization => CWE-502}/UnsafeDeserialization.qhelp (100%) rename python/ql/src/Security/{Injection/UnsafeDeserialization => CWE-502}/UnsafeDeserialization.ql (100%) rename python/ql/src/Security/{Injection/OpenRedirect/OpenRedirect.qhelp => CWE-601/UrlRedirect.qhelp} (100%) rename python/ql/src/Security/{Injection/OpenRedirect/OpenRedirect.ql => CWE-601/UrlRedirect.ql} (100%) rename python/ql/src/Security/{Injection/OpenRedirect => CWE-601}/examples/redirect_bad.py (100%) rename python/ql/src/Security/{Injection/OpenRedirect => CWE-601}/examples/redirect_good.py (100%) rename python/ql/src/Security/{BadPractice/WeakFilePermissions => CWE-732}/WeakFilePermissions.qhelp (100%) rename python/ql/src/Security/{BadPractice/WeakFilePermissions => CWE-732}/WeakFilePermissions.ql (100%) rename python/ql/src/Security/{BadPractice/HardcodedCredentials => CWE-798}/HardcodedCredentials.py (100%) rename python/ql/src/Security/{BadPractice/HardcodedCredentials => CWE-798}/HardcodedCredentials.qhelp (100%) rename python/ql/src/Security/{BadPractice/HardcodedCredentials => CWE-798}/HardcodedCredentials.ql (100%) delete mode 100644 python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options delete mode 100644 python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options delete mode 100644 python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options delete mode 100644 python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options delete mode 100644 python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qlref delete mode 100644 python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options rename python/ql/test/query-tests/Security/{BadPractice/BindToAllInterfaces => CVE-2018-1281}/BindToAllInterfaces.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref rename python/ql/test/query-tests/Security/{BadPractice/BindToAllInterfaces => CVE-2018-1281}/BindToAllInterfaces_test.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/BindToAllInterfaces => CVE-2018-1281}/options (100%) rename python/ql/test/query-tests/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/ExternalAPIsUsedWithUntrustedData.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref rename python/ql/test/query-tests/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/UntrustedDataToExternalAPI.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref rename python/ql/test/query-tests/Security/{ExternalAPIs => CWE-020-ExternalAPIs}/test.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/IncompleteHostnameRegExp.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref rename python/ql/test/query-tests/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/IncompleteUrlSubstringSanitization.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref rename python/ql/test/query-tests/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/hosttest.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/IncompleteUrlSanitizer => CWE-020}/urltest.py (100%) rename python/ql/test/query-tests/Security/{Injection/PathInjection => CWE-022-PathInjection}/PathInjection.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref rename python/ql/test/query-tests/Security/{Injection/PathInjection => CWE-022-PathInjection}/path_injection.py (100%) rename python/ql/test/query-tests/Security/{Injection/PathInjection => CWE-022-PathInjection}/test.py (100%) rename python/ql/test/query-tests/Security/{Injection/PathInjection => CWE-022-PathInjection}/test_chaining.py (100%) rename python/ql/test/query-tests/Security/{Injection/TarSlip => CWE-022-TarSlip}/TarSlip.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref rename python/ql/test/query-tests/Security/{BadPractice/Jinja2RenderWithoutEscape => CWE-022-TarSlip}/options (100%) rename python/ql/test/query-tests/Security/{Injection/TarSlip => CWE-022-TarSlip}/tarslip.py (100%) rename python/ql/test/query-tests/Security/{Injection/CommandInjection-py2 => CWE-078-py2}/CommandInjection.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref rename python/ql/test/query-tests/Security/{Injection/CommandInjection-py2 => CWE-078-py2}/command_injection.py (100%) rename python/ql/test/query-tests/Security/{Injection/CommandInjection-py2 => CWE-078-py2}/options (100%) rename python/ql/test/query-tests/Security/{Injection/CommandInjection => CWE-078}/CommandInjection.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref rename python/ql/test/query-tests/Security/{Injection/CommandInjection => CWE-078}/command_injection.py (100%) rename python/ql/test/query-tests/Security/{Injection/CommandInjection => CWE-078}/options (100%) rename python/ql/test/query-tests/Security/{BadPractice/Jinja2RenderWithoutEscape => CWE-079}/Jinja2WithoutEscaping.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref rename python/ql/test/query-tests/Security/{Injection/ReflectedXss => CWE-079}/ReflectedXss.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref rename python/ql/test/query-tests/Security/{BadPractice/Jinja2RenderWithoutEscape => CWE-079}/jinja2_escaping.py (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-079/options rename python/ql/test/query-tests/Security/{Injection/ReflectedXss => CWE-079}/reflected_xss.py (100%) rename python/ql/test/query-tests/Security/{Injection/SqlInjection => CWE-089}/SqlInjection.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref rename python/ql/test/query-tests/Security/{Injection/SqlInjection => CWE-089}/sql_injection.py (100%) rename python/ql/test/query-tests/Security/{Injection/CodeInjection => CWE-094}/CodeInjection.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref rename python/ql/test/query-tests/Security/{Injection/CodeInjection => CWE-094}/code_injection.py (100%) rename python/ql/test/query-tests/Security/{Exposure/StackTraceExposure => CWE-209}/StackTraceExposure.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-209/options rename python/ql/test/query-tests/Security/{Exposure/StackTraceExposure => CWE-209}/test.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/FlaskRunWithDebug => CWE-215}/FlaskDebug.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-215/options rename python/ql/test/query-tests/Security/{BadPractice/FlaskRunWithDebug => CWE-215}/test.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/SSHMissingHostKeyValidation => CWE-295}/MissingHostKeyValidation.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref rename python/ql/test/query-tests/Security/{BadPractice/HTTPSRequestWithoutCertValidation => CWE-295}/RequestWithoutValidation.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref rename python/ql/test/query-tests/Security/{BadPractice/HTTPSRequestWithoutCertValidation => CWE-295}/make_request.py (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-295/options rename python/ql/test/query-tests/Security/{BadPractice/SSHMissingHostKeyValidation => CWE-295}/paramiko_host_key.py (100%) rename python/ql/test/query-tests/Security/{Exposure/SensitiveDataExposure => CWE-312}/CleartextLogging.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref rename python/ql/test/query-tests/Security/{Exposure/SensitiveDataExposure => CWE-312}/CleartextStorage.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-312/options rename python/ql/test/query-tests/Security/{Exposure/SensitiveDataExposure => CWE-312}/password_in_cookie.py (100%) rename python/ql/test/query-tests/Security/{Exposure/SensitiveDataExposure => CWE-312}/test.py (100%) rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoKey => CWE-326}/WeakCrypto.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-326/options rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoKey => CWE-326}/weak_crypto.py (100%) rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoAlgorithm => CWE-327}/BrokenCryptoAlgorithm.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref rename python/ql/test/query-tests/Security/{Crypto/TLS => CWE-327}/InsecureDefaultProtocol.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref rename python/ql/test/query-tests/Security/{Crypto/TLS => CWE-327}/InsecureProtocol.expected (100%) rename python/ql/test/query-tests/Security/{Crypto/TLS => CWE-327}/InsecureProtocol.py (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoAlgorithm => CWE-327}/TestNode.expected (100%) rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoAlgorithm => CWE-327}/TestNode.ql (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-327/options rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoAlgorithm => CWE-327}/test_cryptography.py (100%) rename python/ql/test/query-tests/Security/{Crypto/WeakCryptoAlgorithm => CWE-327}/test_pycrypto.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.expected (100%) rename python/ql/test/query-tests/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/InsecureTemporaryFile.py (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref rename python/ql/test/query-tests/Security/{BadPractice/InsecureTemporaryFile => CWE-377}/SecureTemporaryFile.py (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-377/options rename python/ql/test/query-tests/Security/{Injection/UnsafeDeserialization => CWE-502}/UnsafeDeserialization.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref rename python/ql/test/query-tests/Security/{Injection/UnsafeDeserialization => CWE-502}/unsafe_deserialization.py (100%) rename python/ql/test/query-tests/Security/{Injection/OpenRedirect => CWE-601}/UrlRedirect.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-601/options rename python/ql/test/query-tests/Security/{Injection/OpenRedirect => CWE-601}/test.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/WeakFilePermissions => CWE-732}/WeakFilePermissions.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref create mode 100644 python/ql/test/query-tests/Security/CWE-732/options rename python/ql/test/query-tests/Security/{BadPractice/WeakFilePermissions => CWE-732}/test.py (100%) rename python/ql/test/query-tests/Security/{BadPractice/HardcodedCredentials => CWE-798}/HardcodedCredentials.expected (100%) create mode 100644 python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref rename python/ql/test/query-tests/Security/{BadPractice/HardcodedCredentials => CWE-798}/test.py (100%) delete mode 100644 python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.qlref delete mode 100644 python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref delete mode 100644 python/ql/test/query-tests/Security/Crypto/TLS/options delete mode 100644 python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref delete mode 100644 python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options delete mode 100644 python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref delete mode 100644 python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options delete mode 100644 python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref delete mode 100644 python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref delete mode 100644 python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options delete mode 100644 python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.qlref delete mode 100644 python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options delete mode 100644 python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref delete mode 100644 python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/OpenRedirect/options delete mode 100644 python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.qlref delete mode 100644 python/ql/test/query-tests/Security/Injection/TarSlip/options delete mode 100644 python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qlref diff --git a/python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.py b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py similarity index 100% rename from python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.py rename to python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.py diff --git a/python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qhelp b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qhelp rename to python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.qhelp diff --git a/python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql b/python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql similarity index 100% rename from python/ql/src/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql rename to python/ql/src/Security/CVE-2018-1281/BindToAllInterfaces.ql diff --git a/python/ql/src/Security/ExternalAPIs/ExternalAPISinkExample.py b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPISinkExample.py similarity index 100% rename from python/ql/src/Security/ExternalAPIs/ExternalAPISinkExample.py rename to python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPISinkExample.py diff --git a/python/ql/src/Security/ExternalAPIs/ExternalAPITaintStepExample.py b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPITaintStepExample.py similarity index 100% rename from python/ql/src/Security/ExternalAPIs/ExternalAPITaintStepExample.py rename to python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPITaintStepExample.py diff --git a/python/ql/src/Security/ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll similarity index 98% rename from python/ql/src/Security/ExternalAPIs/ExternalAPIs.qll rename to python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index b3482012e9a..da52edd6af1 100644 --- a/python/ql/src/Security/ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -41,7 +41,6 @@ private import semmle.python.objects.ObjectInternal * A callable that is considered a "safe" external API from a security perspective. */ class SafeExternalAPI extends Unit { - /** Gets a callable that is considered a "safe" external API from a security perspective. */ abstract DataFlowPrivate::DataFlowCallable getSafeCallable(); } diff --git a/python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp similarity index 100% rename from python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp rename to python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qhelp diff --git a/python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql similarity index 100% rename from python/ql/src/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql rename to python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.qhelp b/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp similarity index 100% rename from python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.qhelp rename to python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qhelp diff --git a/python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.ql b/python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql similarity index 100% rename from python/ql/src/Security/ExternalAPIs/UntrustedDataToExternalAPI.ql rename to python/ql/src/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qhelp b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qhelp rename to python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp diff --git a/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql similarity index 100% rename from python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql rename to python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.ql diff --git a/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qhelp b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qhelp rename to python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp diff --git a/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql similarity index 100% rename from python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql rename to python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.ql diff --git a/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteHostnameRegExp.py b/python/ql/src/Security/CWE-020/examples/IncompleteHostnameRegExp.py similarity index 100% rename from python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteHostnameRegExp.py rename to python/ql/src/Security/CWE-020/examples/IncompleteHostnameRegExp.py diff --git a/python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteUrlSubstringSanitization.py b/python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py similarity index 100% rename from python/ql/src/Security/BadPractice/IncompleteUrlSanitizer/examples/IncompleteUrlSubstringSanitization.py rename to python/ql/src/Security/CWE-020/examples/IncompleteUrlSubstringSanitization.py diff --git a/python/ql/src/Security/Injection/PathInjection/PathInjection.qhelp b/python/ql/src/Security/CWE-022/PathInjection.qhelp similarity index 100% rename from python/ql/src/Security/Injection/PathInjection/PathInjection.qhelp rename to python/ql/src/Security/CWE-022/PathInjection.qhelp diff --git a/python/ql/src/Security/Injection/PathInjection/PathInjection.ql b/python/ql/src/Security/CWE-022/PathInjection.ql similarity index 100% rename from python/ql/src/Security/Injection/PathInjection/PathInjection.ql rename to python/ql/src/Security/CWE-022/PathInjection.ql diff --git a/python/ql/src/Security/Injection/TarSlip/TarSlip.qhelp b/python/ql/src/Security/CWE-022/TarSlip.qhelp similarity index 100% rename from python/ql/src/Security/Injection/TarSlip/TarSlip.qhelp rename to python/ql/src/Security/CWE-022/TarSlip.qhelp diff --git a/python/ql/src/Security/Injection/TarSlip/TarSlip.ql b/python/ql/src/Security/CWE-022/TarSlip.ql similarity index 100% rename from python/ql/src/Security/Injection/TarSlip/TarSlip.ql rename to python/ql/src/Security/CWE-022/TarSlip.ql diff --git a/python/ql/src/Security/Injection/PathInjection/examples/tainted_path.py b/python/ql/src/Security/CWE-022/examples/tainted_path.py similarity index 100% rename from python/ql/src/Security/Injection/PathInjection/examples/tainted_path.py rename to python/ql/src/Security/CWE-022/examples/tainted_path.py diff --git a/python/ql/src/Security/Injection/TarSlip/examples/tarslip_bad.py b/python/ql/src/Security/CWE-022/examples/tarslip_bad.py similarity index 100% rename from python/ql/src/Security/Injection/TarSlip/examples/tarslip_bad.py rename to python/ql/src/Security/CWE-022/examples/tarslip_bad.py diff --git a/python/ql/src/Security/Injection/TarSlip/examples/tarslip_good.py b/python/ql/src/Security/CWE-022/examples/tarslip_good.py similarity index 100% rename from python/ql/src/Security/Injection/TarSlip/examples/tarslip_good.py rename to python/ql/src/Security/CWE-022/examples/tarslip_good.py diff --git a/python/ql/src/Security/Injection/CommandInjection/CommandInjection.qhelp b/python/ql/src/Security/CWE-078/CommandInjection.qhelp similarity index 100% rename from python/ql/src/Security/Injection/CommandInjection/CommandInjection.qhelp rename to python/ql/src/Security/CWE-078/CommandInjection.qhelp diff --git a/python/ql/src/Security/Injection/CommandInjection/CommandInjection.ql b/python/ql/src/Security/CWE-078/CommandInjection.ql similarity index 100% rename from python/ql/src/Security/Injection/CommandInjection/CommandInjection.ql rename to python/ql/src/Security/CWE-078/CommandInjection.ql diff --git a/python/ql/src/Security/Injection/CommandInjection/examples/command_injection.py b/python/ql/src/Security/CWE-078/examples/command_injection.py similarity index 100% rename from python/ql/src/Security/Injection/CommandInjection/examples/command_injection.py rename to python/ql/src/Security/CWE-078/examples/command_injection.py diff --git a/python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qhelp b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qhelp rename to python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.qhelp diff --git a/python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.ql b/python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql similarity index 100% rename from python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.ql rename to python/ql/src/Security/CWE-079/Jinja2WithoutEscaping.ql diff --git a/python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.qhelp b/python/ql/src/Security/CWE-079/ReflectedXss.qhelp similarity index 100% rename from python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.qhelp rename to python/ql/src/Security/CWE-079/ReflectedXss.qhelp diff --git a/python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.ql b/python/ql/src/Security/CWE-079/ReflectedXss.ql similarity index 100% rename from python/ql/src/Security/Injection/ReflectedXss/ReflectedXss.ql rename to python/ql/src/Security/CWE-079/ReflectedXss.ql diff --git a/python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/examples/jinja2.py b/python/ql/src/Security/CWE-079/examples/jinja2.py similarity index 100% rename from python/ql/src/Security/BadPractice/Jinja2RenderWithoutEscape/examples/jinja2.py rename to python/ql/src/Security/CWE-079/examples/jinja2.py diff --git a/python/ql/src/Security/Injection/ReflectedXss/examples/xss.py b/python/ql/src/Security/CWE-079/examples/xss.py similarity index 100% rename from python/ql/src/Security/Injection/ReflectedXss/examples/xss.py rename to python/ql/src/Security/CWE-079/examples/xss.py diff --git a/python/ql/src/Security/Injection/SqlInjection/SqlInjection.qhelp b/python/ql/src/Security/CWE-089/SqlInjection.qhelp similarity index 100% rename from python/ql/src/Security/Injection/SqlInjection/SqlInjection.qhelp rename to python/ql/src/Security/CWE-089/SqlInjection.qhelp diff --git a/python/ql/src/Security/Injection/SqlInjection/SqlInjection.ql b/python/ql/src/Security/CWE-089/SqlInjection.ql similarity index 100% rename from python/ql/src/Security/Injection/SqlInjection/SqlInjection.ql rename to python/ql/src/Security/CWE-089/SqlInjection.ql diff --git a/python/ql/src/Security/Injection/SqlInjection/examples/sql_injection.py b/python/ql/src/Security/CWE-089/examples/sql_injection.py similarity index 100% rename from python/ql/src/Security/Injection/SqlInjection/examples/sql_injection.py rename to python/ql/src/Security/CWE-089/examples/sql_injection.py diff --git a/python/ql/src/Security/Injection/CodeInjection/CodeInjection.qhelp b/python/ql/src/Security/CWE-094/CodeInjection.qhelp similarity index 100% rename from python/ql/src/Security/Injection/CodeInjection/CodeInjection.qhelp rename to python/ql/src/Security/CWE-094/CodeInjection.qhelp diff --git a/python/ql/src/Security/Injection/CodeInjection/CodeInjection.ql b/python/ql/src/Security/CWE-094/CodeInjection.ql similarity index 100% rename from python/ql/src/Security/Injection/CodeInjection/CodeInjection.ql rename to python/ql/src/Security/CWE-094/CodeInjection.ql diff --git a/python/ql/src/Security/Injection/CodeInjection/examples/code_injection.py b/python/ql/src/Security/CWE-094/examples/code_injection.py similarity index 100% rename from python/ql/src/Security/Injection/CodeInjection/examples/code_injection.py rename to python/ql/src/Security/CWE-094/examples/code_injection.py diff --git a/python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.py b/python/ql/src/Security/CWE-209/StackTraceExposure.py similarity index 100% rename from python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.py rename to python/ql/src/Security/CWE-209/StackTraceExposure.py diff --git a/python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.qhelp b/python/ql/src/Security/CWE-209/StackTraceExposure.qhelp similarity index 100% rename from python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.qhelp rename to python/ql/src/Security/CWE-209/StackTraceExposure.qhelp diff --git a/python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.ql b/python/ql/src/Security/CWE-209/StackTraceExposure.ql similarity index 100% rename from python/ql/src/Security/Exposure/StackTraceExposure/StackTraceExposure.ql rename to python/ql/src/Security/CWE-209/StackTraceExposure.ql diff --git a/python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.py b/python/ql/src/Security/CWE-215/FlaskDebug.py similarity index 100% rename from python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.py rename to python/ql/src/Security/CWE-215/FlaskDebug.py diff --git a/python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qhelp b/python/ql/src/Security/CWE-215/FlaskDebug.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qhelp rename to python/ql/src/Security/CWE-215/FlaskDebug.qhelp diff --git a/python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.ql b/python/ql/src/Security/CWE-215/FlaskDebug.ql similarity index 100% rename from python/ql/src/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.ql rename to python/ql/src/Security/CWE-215/FlaskDebug.ql diff --git a/python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.qhelp b/python/ql/src/Security/CWE-295/MissingHostKeyValidation.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.qhelp rename to python/ql/src/Security/CWE-295/MissingHostKeyValidation.qhelp diff --git a/python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql b/python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql similarity index 100% rename from python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql rename to python/ql/src/Security/CWE-295/MissingHostKeyValidation.ql diff --git a/python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.qhelp b/python/ql/src/Security/CWE-295/RequestWithoutValidation.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.qhelp rename to python/ql/src/Security/CWE-295/RequestWithoutValidation.qhelp diff --git a/python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql b/python/ql/src/Security/CWE-295/RequestWithoutValidation.ql similarity index 100% rename from python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql rename to python/ql/src/Security/CWE-295/RequestWithoutValidation.ql diff --git a/python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/examples/make_request.py b/python/ql/src/Security/CWE-295/examples/make_request.py similarity index 100% rename from python/ql/src/Security/BadPractice/HTTPSRequestWithoutCertValidation/examples/make_request.py rename to python/ql/src/Security/CWE-295/examples/make_request.py diff --git a/python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/examples/paramiko_host_key.py b/python/ql/src/Security/CWE-295/examples/paramiko_host_key.py similarity index 100% rename from python/ql/src/Security/BadPractice/SSHMissingHostKeyValidation/examples/paramiko_host_key.py rename to python/ql/src/Security/CWE-295/examples/paramiko_host_key.py diff --git a/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.qhelp b/python/ql/src/Security/CWE-312/CleartextLogging.qhelp similarity index 100% rename from python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.qhelp rename to python/ql/src/Security/CWE-312/CleartextLogging.qhelp diff --git a/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.ql b/python/ql/src/Security/CWE-312/CleartextLogging.ql similarity index 100% rename from python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextLogging.ql rename to python/ql/src/Security/CWE-312/CleartextLogging.ql diff --git a/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.qhelp b/python/ql/src/Security/CWE-312/CleartextStorage.qhelp similarity index 100% rename from python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.qhelp rename to python/ql/src/Security/CWE-312/CleartextStorage.qhelp diff --git a/python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.ql b/python/ql/src/Security/CWE-312/CleartextStorage.ql similarity index 100% rename from python/ql/src/Security/Exposure/SensitiveDataExposure/CleartextStorage.ql rename to python/ql/src/Security/CWE-312/CleartextStorage.ql diff --git a/python/ql/src/Security/Exposure/SensitiveDataExposure/examples/password_in_cookie.py b/python/ql/src/Security/CWE-312/examples/password_in_cookie.py similarity index 100% rename from python/ql/src/Security/Exposure/SensitiveDataExposure/examples/password_in_cookie.py rename to python/ql/src/Security/CWE-312/examples/password_in_cookie.py diff --git a/python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.qhelp b/python/ql/src/Security/CWE-326/WeakCrypto.qhelp similarity index 100% rename from python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.qhelp rename to python/ql/src/Security/CWE-326/WeakCrypto.qhelp diff --git a/python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.ql b/python/ql/src/Security/CWE-326/WeakCrypto.ql similarity index 100% rename from python/ql/src/Security/Crypto/WeakCryptoKey/WeakCryptoKey.ql rename to python/ql/src/Security/CWE-326/WeakCrypto.ql diff --git a/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp similarity index 97% rename from python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp rename to python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp index 01c8460d14c..ba5ab4d10c1 100644 --- a/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.qhelp +++ b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -36,7 +36,7 @@ example uses AES, which is a stronger modern algorithm.

    - +

    WARNING: Although the second example above is more robust, diff --git a/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql b/python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql similarity index 100% rename from python/ql/src/Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql rename to python/ql/src/Security/CWE-327/BrokenCryptoAlgorithm.ql diff --git a/python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.qhelp b/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.qhelp similarity index 100% rename from python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.qhelp rename to python/ql/src/Security/CWE-327/InsecureDefaultProtocol.qhelp diff --git a/python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.ql b/python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql similarity index 100% rename from python/ql/src/Security/Crypto/TLS/InsecureDefaultProtocol.ql rename to python/ql/src/Security/CWE-327/InsecureDefaultProtocol.ql diff --git a/python/ql/src/Security/Crypto/TLS/InsecureProtocol.qhelp b/python/ql/src/Security/CWE-327/InsecureProtocol.qhelp similarity index 100% rename from python/ql/src/Security/Crypto/TLS/InsecureProtocol.qhelp rename to python/ql/src/Security/CWE-327/InsecureProtocol.qhelp diff --git a/python/ql/src/Security/Crypto/TLS/InsecureProtocol.ql b/python/ql/src/Security/CWE-327/InsecureProtocol.ql similarity index 100% rename from python/ql/src/Security/Crypto/TLS/InsecureProtocol.ql rename to python/ql/src/Security/CWE-327/InsecureProtocol.ql diff --git a/python/ql/src/Security/Crypto/WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py b/python/ql/src/Security/CWE-327/examples/broken_crypto.py similarity index 100% rename from python/ql/src/Security/Crypto/WeakCryptoAlgorithm/examples/weak_crypto_algorithm.py rename to python/ql/src/Security/CWE-327/examples/broken_crypto.py diff --git a/python/ql/src/Security/Crypto/TLS/examples/insecure_default_protocol.py b/python/ql/src/Security/CWE-327/examples/insecure_default_protocol.py similarity index 100% rename from python/ql/src/Security/Crypto/TLS/examples/insecure_default_protocol.py rename to python/ql/src/Security/CWE-327/examples/insecure_default_protocol.py diff --git a/python/ql/src/Security/Crypto/TLS/examples/insecure_protocol.py b/python/ql/src/Security/CWE-327/examples/insecure_protocol.py similarity index 100% rename from python/ql/src/Security/Crypto/TLS/examples/insecure_protocol.py rename to python/ql/src/Security/CWE-327/examples/insecure_protocol.py diff --git a/python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py b/python/ql/src/Security/CWE-377/InsecureTemporaryFile.py similarity index 100% rename from python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py rename to python/ql/src/Security/CWE-377/InsecureTemporaryFile.py diff --git a/python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qhelp b/python/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qhelp rename to python/ql/src/Security/CWE-377/InsecureTemporaryFile.qhelp diff --git a/python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.ql b/python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql similarity index 100% rename from python/ql/src/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.ql rename to python/ql/src/Security/CWE-377/InsecureTemporaryFile.ql diff --git a/python/ql/src/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py b/python/ql/src/Security/CWE-377/SecureTemporaryFile.py similarity index 100% rename from python/ql/src/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py rename to python/ql/src/Security/CWE-377/SecureTemporaryFile.py diff --git a/python/ql/src/Security/Injection/UnsafeDeserialization/JsonGood.py b/python/ql/src/Security/CWE-502/JsonGood.py similarity index 100% rename from python/ql/src/Security/Injection/UnsafeDeserialization/JsonGood.py rename to python/ql/src/Security/CWE-502/JsonGood.py diff --git a/python/ql/src/Security/Injection/UnsafeDeserialization/UnpicklingBad.py b/python/ql/src/Security/CWE-502/UnpicklingBad.py similarity index 100% rename from python/ql/src/Security/Injection/UnsafeDeserialization/UnpicklingBad.py rename to python/ql/src/Security/CWE-502/UnpicklingBad.py diff --git a/python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qhelp b/python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp similarity index 100% rename from python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qhelp rename to python/ql/src/Security/CWE-502/UnsafeDeserialization.qhelp diff --git a/python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.ql b/python/ql/src/Security/CWE-502/UnsafeDeserialization.ql similarity index 100% rename from python/ql/src/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.ql rename to python/ql/src/Security/CWE-502/UnsafeDeserialization.ql diff --git a/python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.qhelp b/python/ql/src/Security/CWE-601/UrlRedirect.qhelp similarity index 100% rename from python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.qhelp rename to python/ql/src/Security/CWE-601/UrlRedirect.qhelp diff --git a/python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.ql b/python/ql/src/Security/CWE-601/UrlRedirect.ql similarity index 100% rename from python/ql/src/Security/Injection/OpenRedirect/OpenRedirect.ql rename to python/ql/src/Security/CWE-601/UrlRedirect.ql diff --git a/python/ql/src/Security/Injection/OpenRedirect/examples/redirect_bad.py b/python/ql/src/Security/CWE-601/examples/redirect_bad.py similarity index 100% rename from python/ql/src/Security/Injection/OpenRedirect/examples/redirect_bad.py rename to python/ql/src/Security/CWE-601/examples/redirect_bad.py diff --git a/python/ql/src/Security/Injection/OpenRedirect/examples/redirect_good.py b/python/ql/src/Security/CWE-601/examples/redirect_good.py similarity index 100% rename from python/ql/src/Security/Injection/OpenRedirect/examples/redirect_good.py rename to python/ql/src/Security/CWE-601/examples/redirect_good.py diff --git a/python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qhelp b/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qhelp rename to python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp diff --git a/python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.ql b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql similarity index 100% rename from python/ql/src/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.ql rename to python/ql/src/Security/CWE-732/WeakFilePermissions.ql diff --git a/python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.py b/python/ql/src/Security/CWE-798/HardcodedCredentials.py similarity index 100% rename from python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.py rename to python/ql/src/Security/CWE-798/HardcodedCredentials.py diff --git a/python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qhelp b/python/ql/src/Security/CWE-798/HardcodedCredentials.qhelp similarity index 100% rename from python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qhelp rename to python/ql/src/Security/CWE-798/HardcodedCredentials.qhelp diff --git a/python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql b/python/ql/src/Security/CWE-798/HardcodedCredentials.ql similarity index 100% rename from python/ql/src/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql rename to python/ql/src/Security/CWE-798/HardcodedCredentials.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref b/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref deleted file mode 100644 index adef42d0768..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref deleted file mode 100644 index 67a0f7a60de..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/FlaskRunWithDebug/FlaskDebug.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options b/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options deleted file mode 100644 index e552c11e561..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../../lib diff --git a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.qlref b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.qlref deleted file mode 100644 index c8e27ca0561..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/HTTPSRequestWithoutCertValidation/HTTPSRequestWithoutCertValidation.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options b/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref deleted file mode 100644 index ff70ade48e7..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/HardcodedCredentials/HardcodedCredentials.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref deleted file mode 100644 index 2fac15c1228..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref deleted file mode 100644 index 00a3a8dad07..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qlref b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qlref deleted file mode 100644 index ee6d466921c..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options b/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref b/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref deleted file mode 100644 index 4cdcd0c5567..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref deleted file mode 100644 index 174098ffea7..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/SSHMissingHostKeyValidation/SSHMissingHostKeyValidation.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options b/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qlref deleted file mode 100644 index 8a8619a4a2d..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/BadPractice/WeakFilePermissions/WeakFilePermissions.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options b/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options deleted file mode 100644 index e552c11e561..00000000000 --- a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --max-import-depth=2 -p ../../lib diff --git a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.expected b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces.expected rename to python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.expected diff --git a/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref new file mode 100644 index 00000000000..f06cc3d869d --- /dev/null +++ b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces.qlref @@ -0,0 +1 @@ +Security/CVE-2018-1281/BindToAllInterfaces.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces_test.py b/python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/BindToAllInterfaces_test.py rename to python/ql/test/query-tests/Security/CVE-2018-1281/BindToAllInterfaces_test.py diff --git a/python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/options b/python/ql/test/query-tests/Security/CVE-2018-1281/options similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/BindToAllInterfaces/options rename to python/ql/test/query-tests/Security/CVE-2018-1281/options diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected similarity index 100% rename from python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected rename to python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.expected diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref new file mode 100644 index 00000000000..c91bf44f815 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref @@ -0,0 +1 @@ +Security/CWE-020-ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.expected b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected similarity index 100% rename from python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.expected rename to python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.expected diff --git a/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref new file mode 100644 index 00000000000..03c06feeec8 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.qlref @@ -0,0 +1 @@ +Security/CWE-020-ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/test.py b/python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py similarity index 100% rename from python/ql/test/query-tests/Security/ExternalAPIs/test.py rename to python/ql/test/query-tests/Security/CWE-020-ExternalAPIs/test.py diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.expected b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteHostnameRegExp.expected rename to python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.expected diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref new file mode 100644 index 00000000000..e818d947252 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp.qlref @@ -0,0 +1 @@ +Security/CWE-020/IncompleteHostnameRegExp.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.expected b/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/IncompleteUrlSubstringSanitization.expected rename to python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.expected diff --git a/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref b/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref new file mode 100644 index 00000000000..3fa6794419d --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-020/IncompleteUrlSubstringSanitization.qlref @@ -0,0 +1 @@ +Security/CWE-020/IncompleteUrlSubstringSanitization.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/hosttest.py b/python/ql/test/query-tests/Security/CWE-020/hosttest.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/hosttest.py rename to python/ql/test/query-tests/Security/CWE-020/hosttest.py diff --git a/python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/urltest.py b/python/ql/test/query-tests/Security/CWE-020/urltest.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/IncompleteUrlSanitizer/urltest.py rename to python/ql/test/query-tests/Security/CWE-020/urltest.py diff --git a/python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.expected b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.expected rename to python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref new file mode 100644 index 00000000000..d43482cc509 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/PathInjection.qlref @@ -0,0 +1 @@ +Security/CWE-022/PathInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/PathInjection/path_injection.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/PathInjection/path_injection.py rename to python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py diff --git a/python/ql/test/query-tests/Security/Injection/PathInjection/test.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/PathInjection/test.py rename to python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py diff --git a/python/ql/test/query-tests/Security/Injection/PathInjection/test_chaining.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/PathInjection/test_chaining.py rename to python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.expected b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.expected rename to python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.expected diff --git a/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref new file mode 100644 index 00000000000..cfede0c92b2 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-022-TarSlip/TarSlip.qlref @@ -0,0 +1 @@ +Security/CWE-022/TarSlip.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/options b/python/ql/test/query-tests/Security/CWE-022-TarSlip/options similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/options rename to python/ql/test/query-tests/Security/CWE-022-TarSlip/options diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/tarslip.py b/python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/TarSlip/tarslip.py rename to python/ql/test/query-tests/Security/CWE-022-TarSlip/tarslip.py diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.expected rename to python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref new file mode 100644 index 00000000000..e38b88f2919 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-078-py2/CommandInjection.qlref @@ -0,0 +1 @@ +Security/CWE-078/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-py2/command_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CommandInjection-py2/command_injection.py rename to python/ql/test/query-tests/Security/CWE-078-py2/command_injection.py diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/options b/python/ql/test/query-tests/Security/CWE-078-py2/options similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CommandInjection-py2/options rename to python/ql/test/query-tests/Security/CWE-078-py2/options diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.expected b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.expected rename to python/ql/test/query-tests/Security/CWE-078/CommandInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref new file mode 100644 index 00000000000..e38b88f2919 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref @@ -0,0 +1 @@ +Security/CWE-078/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection/command_injection.py b/python/ql/test/query-tests/Security/CWE-078/command_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CommandInjection/command_injection.py rename to python/ql/test/query-tests/Security/CWE-078/command_injection.py diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection/options b/python/ql/test/query-tests/Security/CWE-078/options similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CommandInjection/options rename to python/ql/test/query-tests/Security/CWE-078/options diff --git a/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.expected b/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/Jinja2WithoutEscaping.expected rename to python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.expected diff --git a/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref b/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref new file mode 100644 index 00000000000..9fefcf4a030 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/Jinja2WithoutEscaping.qlref @@ -0,0 +1 @@ +Security/CWE-079/Jinja2WithoutEscaping.ql diff --git a/python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.expected b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.expected rename to python/ql/test/query-tests/Security/CWE-079/ReflectedXss.expected diff --git a/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref new file mode 100644 index 00000000000..e0efe102416 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/ReflectedXss.qlref @@ -0,0 +1 @@ +Security/CWE-079/ReflectedXss.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/jinja2_escaping.py b/python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/Jinja2RenderWithoutEscape/jinja2_escaping.py rename to python/ql/test/query-tests/Security/CWE-079/jinja2_escaping.py diff --git a/python/ql/test/query-tests/Security/CWE-079/options b/python/ql/test/query-tests/Security/CWE-079/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-079/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Injection/ReflectedXss/reflected_xss.py b/python/ql/test/query-tests/Security/CWE-079/reflected_xss.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/ReflectedXss/reflected_xss.py rename to python/ql/test/query-tests/Security/CWE-079/reflected_xss.py diff --git a/python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.expected rename to python/ql/test/query-tests/Security/CWE-089/SqlInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref new file mode 100644 index 00000000000..d1d02cbe8d3 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-089/SqlInjection.qlref @@ -0,0 +1 @@ +Security/CWE-089/SqlInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/SqlInjection/sql_injection.py b/python/ql/test/query-tests/Security/CWE-089/sql_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/SqlInjection/sql_injection.py rename to python/ql/test/query-tests/Security/CWE-089/sql_injection.py diff --git a/python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.expected b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.expected rename to python/ql/test/query-tests/Security/CWE-094/CodeInjection.expected diff --git a/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref new file mode 100644 index 00000000000..fe9adbf3b64 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-094/CodeInjection.qlref @@ -0,0 +1 @@ +Security/CWE-094/CodeInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/CodeInjection/code_injection.py b/python/ql/test/query-tests/Security/CWE-094/code_injection.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/CodeInjection/code_injection.py rename to python/ql/test/query-tests/Security/CWE-094/code_injection.py diff --git a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.expected b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected similarity index 100% rename from python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.expected rename to python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.expected diff --git a/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref new file mode 100644 index 00000000000..18cf2d49a1a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-209/StackTraceExposure.qlref @@ -0,0 +1 @@ +Security/CWE-209/StackTraceExposure.ql diff --git a/python/ql/test/query-tests/Security/CWE-209/options b/python/ql/test/query-tests/Security/CWE-209/options new file mode 100644 index 00000000000..2729d5a143a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-209/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=2 diff --git a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/test.py b/python/ql/test/query-tests/Security/CWE-209/test.py similarity index 100% rename from python/ql/test/query-tests/Security/Exposure/StackTraceExposure/test.py rename to python/ql/test/query-tests/Security/CWE-209/test.py diff --git a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.expected b/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/FlaskDebug.expected rename to python/ql/test/query-tests/Security/CWE-215/FlaskDebug.expected diff --git a/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref b/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref new file mode 100644 index 00000000000..0e21a3ac14f --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-215/FlaskDebug.qlref @@ -0,0 +1 @@ +Security/CWE-215/FlaskDebug.ql diff --git a/python/ql/test/query-tests/Security/CWE-215/options b/python/ql/test/query-tests/Security/CWE-215/options new file mode 100644 index 00000000000..84717fe64cf --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-215/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/test.py b/python/ql/test/query-tests/Security/CWE-215/test.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/FlaskRunWithDebug/test.py rename to python/ql/test/query-tests/Security/CWE-215/test.py diff --git a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.expected b/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/MissingHostKeyValidation.expected rename to python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.expected diff --git a/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref b/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref new file mode 100644 index 00000000000..c366095516a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-295/MissingHostKeyValidation.qlref @@ -0,0 +1 @@ +Security/CWE-295/MissingHostKeyValidation.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.expected b/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/RequestWithoutValidation.expected rename to python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.expected diff --git a/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref b/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref new file mode 100644 index 00000000000..7ad4d4d2ae3 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-295/RequestWithoutValidation.qlref @@ -0,0 +1 @@ +Security/CWE-295/RequestWithoutValidation.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/make_request.py b/python/ql/test/query-tests/Security/CWE-295/make_request.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/HTTPSRequestWithoutCertValidation/make_request.py rename to python/ql/test/query-tests/Security/CWE-295/make_request.py diff --git a/python/ql/test/query-tests/Security/CWE-295/options b/python/ql/test/query-tests/Security/CWE-295/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-295/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/paramiko_host_key.py b/python/ql/test/query-tests/Security/CWE-295/paramiko_host_key.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/SSHMissingHostKeyValidation/paramiko_host_key.py rename to python/ql/test/query-tests/Security/CWE-295/paramiko_host_key.py diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected similarity index 100% rename from python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.expected rename to python/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref b/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref new file mode 100644 index 00000000000..de9273391c8 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-312/CleartextLogging.qlref @@ -0,0 +1 @@ +Security/CWE-312/CleartextLogging.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.expected b/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected similarity index 100% rename from python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.expected rename to python/ql/test/query-tests/Security/CWE-312/CleartextStorage.expected diff --git a/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref b/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref new file mode 100644 index 00000000000..a32206e8d6a --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-312/CleartextStorage.qlref @@ -0,0 +1 @@ +Security/CWE-312/CleartextStorage.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/CWE-312/options b/python/ql/test/query-tests/Security/CWE-312/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-312/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/password_in_cookie.py b/python/ql/test/query-tests/Security/CWE-312/password_in_cookie.py similarity index 100% rename from python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/password_in_cookie.py rename to python/ql/test/query-tests/Security/CWE-312/password_in_cookie.py diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/test.py b/python/ql/test/query-tests/Security/CWE-312/test.py similarity index 100% rename from python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/test.py rename to python/ql/test/query-tests/Security/CWE-312/test.py diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.expected b/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.expected similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.expected rename to python/ql/test/query-tests/Security/CWE-326/WeakCrypto.expected diff --git a/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref b/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref new file mode 100644 index 00000000000..75676139ac3 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-326/WeakCrypto.qlref @@ -0,0 +1 @@ +Security/CWE-326/WeakCrypto.ql diff --git a/python/ql/test/query-tests/Security/CWE-326/options b/python/ql/test/query-tests/Security/CWE-326/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-326/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/weak_crypto.py b/python/ql/test/query-tests/Security/CWE-326/weak_crypto.py similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/weak_crypto.py rename to python/ql/test/query-tests/Security/CWE-326/weak_crypto.py diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.expected b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.expected rename to python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.expected diff --git a/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref new file mode 100644 index 00000000000..3f7aff53700 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/BrokenCryptoAlgorithm.qlref @@ -0,0 +1 @@ +Security/CWE-327/BrokenCryptoAlgorithm.ql diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.expected b/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.expected similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.expected rename to python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.expected diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref new file mode 100644 index 00000000000..13599b14931 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/InsecureDefaultProtocol.qlref @@ -0,0 +1 @@ +Security/CWE-327/InsecureDefaultProtocol.ql diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.expected b/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.expected similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.expected rename to python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.expected diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.py b/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.py similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.py rename to python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.py diff --git a/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref b/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref new file mode 100644 index 00000000000..c06a937ff57 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/InsecureProtocol.qlref @@ -0,0 +1 @@ +Security/CWE-327/InsecureProtocol.ql diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.expected b/python/ql/test/query-tests/Security/CWE-327/TestNode.expected similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.expected rename to python/ql/test/query-tests/Security/CWE-327/TestNode.expected diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.ql b/python/ql/test/query-tests/Security/CWE-327/TestNode.ql similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/TestNode.ql rename to python/ql/test/query-tests/Security/CWE-327/TestNode.ql diff --git a/python/ql/test/query-tests/Security/CWE-327/options b/python/ql/test/query-tests/Security/CWE-327/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-327/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_cryptography.py b/python/ql/test/query-tests/Security/CWE-327/test_cryptography.py similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_cryptography.py rename to python/ql/test/query-tests/Security/CWE-327/test_cryptography.py diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_pycrypto.py b/python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py similarity index 100% rename from python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/test_pycrypto.py rename to python/ql/test/query-tests/Security/CWE-327/test_pycrypto.py diff --git a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.expected b/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.expected rename to python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.expected diff --git a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py b/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/InsecureTemporaryFile.py rename to python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.py diff --git a/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref b/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref new file mode 100644 index 00000000000..68a27dfb269 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-377/InsecureTemporaryFile.qlref @@ -0,0 +1 @@ +Security/CWE-377/InsecureTemporaryFile.ql diff --git a/python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py b/python/ql/test/query-tests/Security/CWE-377/SecureTemporaryFile.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/InsecureTemporaryFile/SecureTemporaryFile.py rename to python/ql/test/query-tests/Security/CWE-377/SecureTemporaryFile.py diff --git a/python/ql/test/query-tests/Security/CWE-377/options b/python/ql/test/query-tests/Security/CWE-377/options new file mode 100644 index 00000000000..492768b3481 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-377/options @@ -0,0 +1 @@ +semmle-extractor-options: -p ../lib/ --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.expected b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.expected rename to python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.expected diff --git a/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref new file mode 100644 index 00000000000..fa9c0ceb3cb --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-502/UnsafeDeserialization.qlref @@ -0,0 +1 @@ +Security/CWE-502/UnsafeDeserialization.ql diff --git a/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/unsafe_deserialization.py b/python/ql/test/query-tests/Security/CWE-502/unsafe_deserialization.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/unsafe_deserialization.py rename to python/ql/test/query-tests/Security/CWE-502/unsafe_deserialization.py diff --git a/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.expected b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected similarity index 100% rename from python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.expected rename to python/ql/test/query-tests/Security/CWE-601/UrlRedirect.expected diff --git a/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref new file mode 100644 index 00000000000..8b63d80f0db --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-601/UrlRedirect.qlref @@ -0,0 +1,2 @@ +Security/CWE-601/UrlRedirect.ql + diff --git a/python/ql/test/query-tests/Security/CWE-601/options b/python/ql/test/query-tests/Security/CWE-601/options new file mode 100644 index 00000000000..28b616e5f19 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-601/options @@ -0,0 +1 @@ +semmle-extractor-options: --lang=3 --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/Injection/OpenRedirect/test.py b/python/ql/test/query-tests/Security/CWE-601/test.py similarity index 100% rename from python/ql/test/query-tests/Security/Injection/OpenRedirect/test.py rename to python/ql/test/query-tests/Security/CWE-601/test.py diff --git a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/WeakFilePermissions.expected rename to python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref new file mode 100644 index 00000000000..9e177187c49 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref @@ -0,0 +1 @@ +Security/CWE-732/WeakFilePermissions.ql diff --git a/python/ql/test/query-tests/Security/CWE-732/options b/python/ql/test/query-tests/Security/CWE-732/options new file mode 100644 index 00000000000..84717fe64cf --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/options @@ -0,0 +1 @@ +semmle-extractor-options: --max-import-depth=2 -p ../lib diff --git a/python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/test.py b/python/ql/test/query-tests/Security/CWE-732/test.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/WeakFilePermissions/test.py rename to python/ql/test/query-tests/Security/CWE-732/test.py diff --git a/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.expected b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/HardcodedCredentials.expected rename to python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected diff --git a/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref new file mode 100644 index 00000000000..0d0fafa271c --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.qlref @@ -0,0 +1 @@ +Security/CWE-798/HardcodedCredentials.ql \ No newline at end of file diff --git a/python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/test.py b/python/ql/test/query-tests/Security/CWE-798/test.py similarity index 100% rename from python/ql/test/query-tests/Security/BadPractice/HardcodedCredentials/test.py rename to python/ql/test/query-tests/Security/CWE-798/test.py diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.qlref b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.qlref deleted file mode 100644 index 899586366e8..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureDefaultProtocol.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Crypto/TLS/InsecureDefaultProtocol.ql diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref b/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref deleted file mode 100644 index 8225a5c47ef..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/TLS/InsecureProtocol.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Crypto/TLS/InsecureProtocol.ql diff --git a/python/ql/test/query-tests/Security/Crypto/TLS/options b/python/ql/test/query-tests/Security/Crypto/TLS/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/TLS/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref deleted file mode 100644 index 4fb0ce84c4d..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/BrokenCryptoAlgorithm.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Crypto/WeakCryptoAlgorithm/WeakCryptoAlgorithm.ql diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options b/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/WeakCryptoAlgorithm/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref deleted file mode 100644 index 18cfd5a12bc..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/WeakCrypto.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Crypto/WeakCryptoKey/WeakCryptoKey.ql diff --git a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options b/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/Crypto/WeakCryptoKey/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref deleted file mode 100644 index e6c1510a3b2..00000000000 --- a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextLogging.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Exposure/SensitiveDataExposure/CleartextLogging.ql diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref deleted file mode 100644 index 63f1d245881..00000000000 --- a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/CleartextStorage.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Exposure/SensitiveDataExposure/CleartextStorage.ql diff --git a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options b/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/Exposure/SensitiveDataExposure/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.qlref b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.qlref deleted file mode 100644 index 927502b954c..00000000000 --- a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/StackTraceExposure.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Exposure/StackTraceExposure/StackTraceExposure.ql diff --git a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options b/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options deleted file mode 100644 index 59cbd921362..00000000000 --- a/python/ql/test/query-tests/Security/Exposure/StackTraceExposure/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=2 diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref b/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref deleted file mode 100644 index 1968cf40cb8..00000000000 --- a/python/ql/test/query-tests/Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/ExternalAPIs/ExternalAPIsUsedWithUntrustedData.ql diff --git a/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref b/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref deleted file mode 100644 index bdbdbdb3ec7..00000000000 --- a/python/ql/test/query-tests/Security/ExternalAPIs/UntrustedDataToExternalAPI.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/ExternalAPIs/UntrustedDataToExternalAPI.ql diff --git a/python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.qlref b/python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.qlref deleted file mode 100644 index f912faeb71a..00000000000 --- a/python/ql/test/query-tests/Security/Injection/CodeInjection/CodeInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/CodeInjection/CodeInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.qlref b/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.qlref deleted file mode 100644 index 91951ea271b..00000000000 --- a/python/ql/test/query-tests/Security/Injection/CommandInjection-py2/CommandInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/CommandInjection/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.qlref b/python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.qlref deleted file mode 100644 index 91951ea271b..00000000000 --- a/python/ql/test/query-tests/Security/Injection/CommandInjection/CommandInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/CommandInjection/CommandInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref b/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref deleted file mode 100644 index 492b7a69453..00000000000 --- a/python/ql/test/query-tests/Security/Injection/OpenRedirect/UrlRedirect.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/OpenRedirect/OpenRedirect.ql diff --git a/python/ql/test/query-tests/Security/Injection/OpenRedirect/options b/python/ql/test/query-tests/Security/Injection/OpenRedirect/options deleted file mode 100644 index 2c9a5f0a13c..00000000000 --- a/python/ql/test/query-tests/Security/Injection/OpenRedirect/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: --lang=3 --max-import-depth=2 -p ../../lib diff --git a/python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.qlref b/python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.qlref deleted file mode 100644 index 510e08f427f..00000000000 --- a/python/ql/test/query-tests/Security/Injection/PathInjection/PathInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/PathInjection/PathInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.qlref b/python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.qlref deleted file mode 100644 index d92b3d701d5..00000000000 --- a/python/ql/test/query-tests/Security/Injection/ReflectedXss/ReflectedXss.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/ReflectedXss/ReflectedXss.ql diff --git a/python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.qlref b/python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.qlref deleted file mode 100644 index c2d12830195..00000000000 --- a/python/ql/test/query-tests/Security/Injection/SqlInjection/SqlInjection.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/SqlInjection/SqlInjection.ql diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.qlref b/python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.qlref deleted file mode 100644 index 178cd6e0a8d..00000000000 --- a/python/ql/test/query-tests/Security/Injection/TarSlip/TarSlip.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/TarSlip/TarSlip.ql diff --git a/python/ql/test/query-tests/Security/Injection/TarSlip/options b/python/ql/test/query-tests/Security/Injection/TarSlip/options deleted file mode 100644 index b7721e6c509..00000000000 --- a/python/ql/test/query-tests/Security/Injection/TarSlip/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options: -p ../../lib --max-import-depth=3 diff --git a/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qlref b/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qlref deleted file mode 100644 index 49f13932a15..00000000000 --- a/python/ql/test/query-tests/Security/Injection/UnsafeDeserialization/UnsafeDeserialization.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/Injection/UnsafeDeserialization/UnsafeDeserialization.ql From 48803504208ca27c7e0acd292cee77846c075b90 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 17 Feb 2021 11:24:11 +0100 Subject: [PATCH 427/429] Python: Add a single missing QLDoc --- python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll index da52edd6af1..b3482012e9a 100644 --- a/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll +++ b/python/ql/src/Security/CWE-020-ExternalAPIs/ExternalAPIs.qll @@ -41,6 +41,7 @@ private import semmle.python.objects.ObjectInternal * A callable that is considered a "safe" external API from a security perspective. */ class SafeExternalAPI extends Unit { + /** Gets a callable that is considered a "safe" external API from a security perspective. */ abstract DataFlowPrivate::DataFlowCallable getSafeCallable(); } From 4df85b44de6aae8848a2eb0813fa6f30b19a38d9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 17 Feb 2021 18:30:31 +0100 Subject: [PATCH 428/429] Update javascript/change-notes/2021-02-10-markdown.md Co-authored-by: Asger F --- javascript/change-notes/2021-02-10-markdown.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/change-notes/2021-02-10-markdown.md b/javascript/change-notes/2021-02-10-markdown.md index ed3dfb505e6..41072ef598f 100644 --- a/javascript/change-notes/2021-02-10-markdown.md +++ b/javascript/change-notes/2021-02-10-markdown.md @@ -1,5 +1,5 @@ lgtm,codescanning -* The dataflow libraries now model dataflow in markdown parsers. +* The security queries now track taint through markdown parsers. Affected packages are [marked](https://npmjs.com/package/marked), [markdown-table](https://npmjs.com/package/markdown-table), From cba9f421ad3ec153c5a6c4167bca5868502c8fab Mon Sep 17 00:00:00 2001 From: "Raul Garcia (MSFT)" Date: Wed, 17 Feb 2021 10:05:22 -0800 Subject: [PATCH 429/429] Changes to the Readme file --- .../Security Features/campaign/Solorigate-Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md b/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md index 9caa17d1f3d..c6bdb98c73e 100644 --- a/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md +++ b/csharp/ql/src/experimental/Security Features/campaign/Solorigate-Readme.md @@ -2,9 +2,9 @@ In early December, 2020 a sophisticated compromise campaign was uncovered, dubbed [Solorigate](https://aka.ms/solorigate). A key feature of the campaign was a malicious software implant inserted into SolarWinds' Orion product on the build server. Studying the coding patterns and techniques used in the implant, Microsoft authored CodeQL queries as part of a larger effort to analyze our source code for any malicious modification - a brief summary of those efforts can be [found here](https://aka.ms/Solorigate-CodeQL-Blog). These queries here represent a mixture of techniques to look for code that shares features with the malicious Implant code. -This ReadMe walks through what each query does and limitations of the approaches taken, suggestions for modifications, and general advice on using CodeQL to author backdoor hunting queries. There are two approaches taken with the queries; the first is to look for syntactic characteristics used in the malicious implant, things like names and particular literals. The second approach looks for semantic patterns – particular functionality and flow associated with the implant. +This ReadMe walks through what each query does and limitations of the approaches taken, suggestions for modifications, and general advice on using CodeQL to author backdoor hunting queries. There are two approaches taken with the queries; the first is to look for syntactic characteristics used in the malicious implant, things like names and particular literals. The second approach looks for semantic patterns – particular functionality and flow associated with the implant. In both cases it is possible, and sometimes likely, that benign code will coincidentally match the patterns these queries look for, so all findings will need to be reviewed to either verify or rule out the providence of the source code being flagged. The descriptions of each query try to capture the likely coincidence of findings in code of benign providence. -When editing this queries for open sourcing, we tried to find the right balance between detection capability and false positive rate, mindful that different organizations have differing resources to review the findings. We also excluded queries that we found to be resource intensive when executing without providing significant detective value over these queries here. In the coming weeks we will post on [our blog](https://aka.ms/CST-SE-Blog) a walk through of our experience authoring and tuning these queries, as well as discussing the challenges we saw with the queries we didn't open source. +When editing this queries for open sourcing, we tried to find the right balance between detection capability and false positive rate, mindful that different organizations have differing resources to review the findings. We also excluded queries that we found to be resource intensive when executing without providing significant detective value over these queries here. ## Syntactic queries