From 8f7ff1a537f6d7fe8f2139ad9dade07fb82ec691 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Mon, 6 Jul 2020 21:45:54 +0200 Subject: [PATCH 001/146] Adds another redundant null check rule --- .../Likely Bugs/RedundantNullCheckParam.cpp | 11 ++++ .../Likely Bugs/RedundantNullCheckParam.qhelp | 29 +++++++++ .../Likely Bugs/RedundantNullCheckParam.ql | 59 +++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp create mode 100644 cpp/ql/src/Likely Bugs/RedundantNullCheckParam.qhelp create mode 100644 cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp new file mode 100644 index 00000000000..5e9c102703d --- /dev/null +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp @@ -0,0 +1,11 @@ +void test(char *arg1, int *arg2) { + if (arg1[0] == 'A') { + if (arg2 != NULL) { + *arg2 = 42; + } + } + if (arg1[1] == 'B') + { + *arg2 = 54; + } +} diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.qhelp b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.qhelp new file mode 100644 index 00000000000..25cbeff355e --- /dev/null +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.qhelp @@ -0,0 +1,29 @@ + + + + +

This rule finds comparisons of a function parameter to null that occur when in another path the parameter is dereferenced without a guard check. It's +likely either the check is not required and can be removed, or it should be added before the dereference +so that a null pointer dereference does not occur.

+
+ + +

A check should be added to before the dereference, in a way that prevents a null pointer value from +being dereferenced. If it's clear that the pointer cannot be null, consider removing the check instead.

+
+ + + + + + +
  • + + Null Dereference + +
  • +
    + +
    diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql new file mode 100644 index 00000000000..c0788dfbcfa --- /dev/null +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql @@ -0,0 +1,59 @@ +/** + * @name Redundant null check or missing null check + * @description Checking a parameter for nullness in one path, + * and not in another is likely to be a sign that either + * the check can be removed, or added in the other case. + * @kind problem + * @id cpp/redundant-null-check-param + * @problem.severity recommendation + * @tags reliability + * security + * external/cwe/cwe-476 + */ + +import cpp + +predicate blockDominates(Block check, Block access) { + check.getLocation().getStartLine() <= access.getLocation().getStartLine() and + check.getLocation().getEndLine() >= access.getLocation().getEndLine() +} + +predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) { + checked = + any(VariableAccess va | + va.getTarget() = unchecked.getTarget() + ) and +//Simple test if the first access in this code path is dereferenced + not dereferenced(checked) and + blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock()) +} + +pragma[noinline] +predicate candidateResultUnchecked(VariableAccess unchecked) { + not isCheckedInstruction(unchecked, _) +} + +pragma[noinline] +predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop, Parameter param) { +//not dereferenced to check against pointer, not its pointed value + not dereferenced(check) and +//assert macros are not taken into account + not check.isInMacroExpansion() and +// is part of a comarison against some constant NULL + eqop.getAnOperand() = check and eqop.getAnOperand() instanceof NullValue and +// this function parameter is not overwritten + count(param.getAnAssignment()) = 0 +} + +from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param +where +// a dereference + dereferenced(unchecked) and +// for a function parameter + unchecked.getTarget() = param and + check.getTarget() = param and +// which is once checked + candidateResultChecked(check, eqop, param) and +// and which has not been checked before in this code path + candidateResultUnchecked(unchecked) +select check, "This null check is redundant because the value is $@ ", unchecked, "dereferenced here" From 5eff8d3165651cbe63b1bff5ea5ec665cc8cb32f Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 9 Jul 2020 11:31:47 +0200 Subject: [PATCH 002/146] Performance improvements suggested --- cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql index c0788dfbcfa..aae04b19f07 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql @@ -28,21 +28,17 @@ predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock()) } -pragma[noinline] predicate candidateResultUnchecked(VariableAccess unchecked) { not isCheckedInstruction(unchecked, _) } -pragma[noinline] -predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop, Parameter param) { +predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) { //not dereferenced to check against pointer, not its pointed value not dereferenced(check) and //assert macros are not taken into account not check.isInMacroExpansion() and // is part of a comarison against some constant NULL - eqop.getAnOperand() = check and eqop.getAnOperand() instanceof NullValue and -// this function parameter is not overwritten - count(param.getAnAssignment()) = 0 + eqop.getAnOperand() = check and eqop.getAnOperand() instanceof NullValue } from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param @@ -51,9 +47,10 @@ where dereferenced(unchecked) and // for a function parameter unchecked.getTarget() = param and - check.getTarget() = param and +// this function parameter is not overwritten + count(param.getAnAssignment()) = 0 and // which is once checked - candidateResultChecked(check, eqop, param) and + candidateResultChecked(check, eqop) and // and which has not been checked before in this code path candidateResultUnchecked(unchecked) select check, "This null check is redundant because the value is $@ ", unchecked, "dereferenced here" From d2763e8149e11cf11eb0d37a0597243995244fbb Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 9 Jul 2020 16:05:24 +0200 Subject: [PATCH 003/146] Comments taken into account --- cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp | 4 ++-- cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp index 5e9c102703d..3765d0b14d4 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp @@ -1,11 +1,11 @@ void test(char *arg1, int *arg2) { if (arg1[0] == 'A') { - if (arg2 != NULL) { + if (arg2 != NULL) { //maybe redundant *arg2 = 42; } } if (arg1[1] == 'B') { - *arg2 = 54; + *arg2 = 54; //dereferenced without checking first } } diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql index aae04b19f07..84d08da6cf0 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql @@ -13,11 +13,6 @@ import cpp -predicate blockDominates(Block check, Block access) { - check.getLocation().getStartLine() <= access.getLocation().getStartLine() and - check.getLocation().getEndLine() >= access.getLocation().getEndLine() -} - predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) { checked = any(VariableAccess va | @@ -25,7 +20,7 @@ predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) ) and //Simple test if the first access in this code path is dereferenced not dereferenced(checked) and - blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock()) + bbDominates(checked.getBasicBlock(), unchecked.getBasicBlock()) } predicate candidateResultUnchecked(VariableAccess unchecked) { From 06c8a0bf2067cd37778de09beb9de470a2802b21 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 9 Jul 2020 16:09:57 +0200 Subject: [PATCH 004/146] move to experimental --- .../{ => experimental}/Likely Bugs/RedundantNullCheckParam.cpp | 0 .../{ => experimental}/Likely Bugs/RedundantNullCheckParam.qhelp | 0 .../src/{ => experimental}/Likely Bugs/RedundantNullCheckParam.ql | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename cpp/ql/src/{ => experimental}/Likely Bugs/RedundantNullCheckParam.cpp (100%) rename cpp/ql/src/{ => experimental}/Likely Bugs/RedundantNullCheckParam.qhelp (100%) rename cpp/ql/src/{ => experimental}/Likely Bugs/RedundantNullCheckParam.ql (100%) diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp similarity index 100% rename from cpp/ql/src/Likely Bugs/RedundantNullCheckParam.cpp rename to cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.cpp diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.qhelp b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.qhelp similarity index 100% rename from cpp/ql/src/Likely Bugs/RedundantNullCheckParam.qhelp rename to cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.qhelp diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql similarity index 100% rename from cpp/ql/src/Likely Bugs/RedundantNullCheckParam.ql rename to cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql From 50f2f69f5f182f799991beff54654adc89c03a86 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 9 Jul 2020 16:14:26 +0200 Subject: [PATCH 005/146] indent comments --- .../Likely Bugs/RedundantNullCheckParam.ql | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql index 84d08da6cf0..71e0b950d6c 100644 --- a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql @@ -1,5 +1,5 @@ /** - * @name Redundant null check or missing null check + * @name Redundant null check or missing null check of parameter * @description Checking a parameter for nullness in one path, * and not in another is likely to be a sign that either * the check can be removed, or added in the other case. @@ -18,7 +18,7 @@ predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) any(VariableAccess va | va.getTarget() = unchecked.getTarget() ) and -//Simple test if the first access in this code path is dereferenced + //Simple test if the first access in this code path is dereferenced not dereferenced(checked) and bbDominates(checked.getBasicBlock(), unchecked.getBasicBlock()) } @@ -28,24 +28,24 @@ predicate candidateResultUnchecked(VariableAccess unchecked) { } predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) { -//not dereferenced to check against pointer, not its pointed value + //not dereferenced to check against pointer, not its pointed value not dereferenced(check) and -//assert macros are not taken into account + //assert macros are not taken into account not check.isInMacroExpansion() and -// is part of a comarison against some constant NULL + // is part of a comparison against some constant NULL eqop.getAnOperand() = check and eqop.getAnOperand() instanceof NullValue } from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param where -// a dereference + // a dereference dereferenced(unchecked) and -// for a function parameter + // for a function parameter unchecked.getTarget() = param and -// this function parameter is not overwritten + // this function parameter is not overwritten count(param.getAnAssignment()) = 0 and -// which is once checked + // which is once checked candidateResultChecked(check, eqop) and -// and which has not been checked before in this code path + // and which has not been checked before in this code path candidateResultUnchecked(unchecked) select check, "This null check is redundant because the value is $@ ", unchecked, "dereferenced here" From 3117c67a66e5a535cc6781948b7d1e9b9307bc9a Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 10 Jul 2020 14:24:24 +0200 Subject: [PATCH 006/146] Updates result message to be more precise --- cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql index 71e0b950d6c..59420957ad5 100644 --- a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql @@ -48,4 +48,4 @@ where candidateResultChecked(check, eqop) and // and which has not been checked before in this code path candidateResultUnchecked(unchecked) -select check, "This null check is redundant because the value is $@ ", unchecked, "dereferenced here" +select check, "This null check is redundant or there is a missing null check before $@ ", unchecked, "where dereferencing happens" From 50b2b12ce288289369b511a6ec8aa01c0fee25bb Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 10 Jul 2020 14:40:58 +0200 Subject: [PATCH 007/146] put back missing condition --- cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql index 59420957ad5..400e8387761 100644 --- a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql @@ -44,6 +44,7 @@ where unchecked.getTarget() = param and // this function parameter is not overwritten count(param.getAnAssignment()) = 0 and + check.getTarget() = param and // which is once checked candidateResultChecked(check, eqop) and // and which has not been checked before in this code path From bf7e3a004e4bef63604fd8b23ec276f3309a78f5 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Fri, 10 Jul 2020 14:58:00 +0200 Subject: [PATCH 008/146] Reverting to enclosing block logic --- .../experimental/Likely Bugs/RedundantNullCheckParam.ql | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql index 400e8387761..d09191a3891 100644 --- a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql @@ -13,6 +13,11 @@ import cpp +predicate blockDominates(Block check, Block access) { + check.getLocation().getStartLine() <= access.getLocation().getStartLine() and + check.getLocation().getEndLine() >= access.getLocation().getEndLine() +} + predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) { checked = any(VariableAccess va | @@ -20,7 +25,7 @@ predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) ) and //Simple test if the first access in this code path is dereferenced not dereferenced(checked) and - bbDominates(checked.getBasicBlock(), unchecked.getBasicBlock()) + blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock()) } predicate candidateResultUnchecked(VariableAccess unchecked) { From c469f71957051e768b8e481867a7194524a6674e Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 26 Jul 2020 22:56:36 +0200 Subject: [PATCH 009/146] Add Codeql query to detect if cookies are sent without the flag being set --- .../Security/CWE-614/InsecureCookie.qhelp | 84 +++++++++ .../Security/CWE-614/InsecureCookie.ql | 19 +++ .../Security/CWE-614/InsecureCookie.qll | 161 ++++++++++++++++++ .../CWE-614/examples/cookie-session_bad.js | 17 ++ .../CWE-614/examples/cookie-session_good.js | 17 ++ .../examples/express-session_bad1_false.js | 7 + .../examples/express-session_bad2_notSet.js | 7 + .../examples/express-session_bad3_setEmpty.js | 7 + .../CWE-614/examples/express-session_bad4.js | 9 + .../CWE-614/examples/express-session_good.js | 9 + .../examples/express_response-cookie_bad1.js | 12 ++ .../examples/express_response-cookie_bad2.js | 12 ++ .../examples/express_response-cookie_good1.js | 12 ++ .../CWE-614/examples/httpserver_bad.js | 8 + .../CWE-614/examples/httpserver_good.js | 8 + .../Security/CWE-614/examples/jsCookie_bad.js | 2 + .../CWE-614/examples/jsCookie_good.js | 2 + 17 files changed, 393 insertions(+) create mode 100644 javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp create mode 100644 javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql create mode 100644 javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js create mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp new file mode 100644 index 00000000000..cff9e878e59 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -0,0 +1,84 @@ + + + +

    Failing to set the 'secure' flag on a cookie can cause it to be sent in cleartext. +This makes it easier for an attacker to intercept.

    +
    + + +

    Always set the secure flag to `true` on a cookie before adding it +to an HTTP response (if the default value is `false`).

    + +
    + + +

    In the first example the `secure` flag is set to `false` using the express middleware `cookie-session`. +In the second example the `secure` flag is set to `true` (it is set `false` by default for HTTP, `true` by default for HTTPS).

    + + + + +
    + + + +

    The first four examples show four ways of adding a cookie using the express middleware `express-session`. +Since the default value for the flag `secure` is false, each example shows a possible scenario where a cookie is set with +the `secure` to `false`. +In the last example the `secure` flag is set to `true`.

    + + + + + + + +
    + + + +

    The first two examples show two ways of adding a cookie using the method `response.cookie`. +In both cases the `secure` flag is to `false`. +In the last example the `secure` flag is set to `true`.

    + + + + + +
    + + + + +

    The first example shows when the `secure` flag is set using the method `Set-Cookie` header of an `HTTP` response. +In this case the `secure` flag is not set. +In the last example the `secure` flag is set.

    + + + + +
    + + + +

    In the first example the `secure` flag is set to `false` using the `js-cookie` library. +In the second example the `secure` flag is set to `true`.

    + + + + +
    + + + +
  • Production Best Practices: Security:Use cookies securely.
  • +
  • NodeJS security cheat sheet:Set cookie flags appropriately.
  • +
  • express-session:cookie.secure.
  • +
  • cookie-session:Cookie Options.
  • +
  • express response.cookie.
  • +
  • Set-Cookie.
  • +
  • js-cookie.
  • +
    +
    diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql new file mode 100644 index 00000000000..228a38d25fa --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -0,0 +1,19 @@ +/** + * @name Failure to set secure cookies + * @description Insecure cookies may be sent in cleartext, which makes them vulnerable to + * interception. + * @kind problem + * @problem.severity error + * @precision high + * @id js/insecure-cookie + * @tags security + * external/cwe/cwe-614 + */ + +import javascript +import InsecureCookie::InsecureCookie + +from InsecureCookies insecureCookies +where insecureCookies.isInsecure() +select "Cookie is added to response without the 'secure' flag being set to true (using " + + insecureCookies.getKind() + ").", insecureCookies diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll new file mode 100644 index 00000000000..82deffa60ca --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -0,0 +1,161 @@ +/** + * Provides classes for reasoning about cookies added to response without the 'secure' flag being set. + * A cookie without the 'secure' flag being set can be intercepted and read by a malicious user. + */ + +import javascript + +module InsecureCookie { + /** + * `secure` property of the cookie options. + */ + string flag() { result = "secure" } + + /** + * Abstract class to represent different cases of insecure cookie settings. + */ + abstract class InsecureCookies extends DataFlow::Node { + /** + * The name of the middleware/library used to set the cookie. + */ + abstract string getKind(); + + /** + * The `cookie` options. + */ + abstract DataFlow::Node getCookieOptionsArgument(); + + /** + * Predicate that determines if a cookie is insecure. + */ + abstract predicate isInsecure(); + } + + /** + * A cookie set using the `express` module `cookie-session` (https://github.com/expressjs/cookie-session). + * The flag `secure` is set to `false` by default for HTTP, `true` by default for HTTPS (https://github.com/expressjs/cookie-session#cookie-options). + */ + class InsecureCookieSession extends ExpressLibraries::CookieSession::MiddlewareInstance, + InsecureCookies { + InsecureCookieSession() { this instanceof ExpressLibraries::CookieSession::MiddlewareInstance } + + override string getKind() { result = "cookie-session" } + + override DataFlow::SourceNode getCookieOptionsArgument() { + result = this.getOption("cookie").(DataFlow::SourceNode) + } + + DataFlow::Node getCookieFlagValue(string flag) { + result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() + } + + // A cookie is insecure if the `secure` flag is explicitly set to `false`. + override predicate isInsecure() { getCookieFlagValue(flag()).mayHaveBooleanValue(false) } + } + + /** + * A cookie set using the `express` module `express-session` (https://github.com/expressjs/session). + * The flag `secure` is not set by default (https://github.com/expressjs/session#cookiesecure). + * The default value for cookie options is { path: '/', httpOnly: true, secure: false, maxAge: null }. + */ + class InsecureExpressSessionCookie extends ExpressLibraries::ExpressSession::MiddlewareInstance, + InsecureCookies { + override string getKind() { result = "express-session" } + + override DataFlow::SourceNode getCookieOptionsArgument() { + result = this.getOption("cookie").(DataFlow::SourceNode) + } + + DataFlow::Node getCookieFlagValue(string flag) { + result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() + } + + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + override predicate isInsecure() { + not exists(DataFlow::SourceNode cookieOptions | + cookieOptions = this.getCookieOptionsArgument() and + getCookieFlagValue(flag()).mayHaveBooleanValue(true) + ) and + not getCookieFlagValue(flag()).mayHaveStringValue("auto") + } + } + + /** + * A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie). + */ + class InsecureExpressCookieResponse extends InsecureCookies { + InsecureExpressCookieResponse() { + this = any(Express::ResponseExpr response).flow().getALocalSource().getAMemberCall("cookie") + } + + override string getKind() { result = "response.cookie" } + + override DataFlow::SourceNode getCookieOptionsArgument() { + result = this.(DataFlow::InvokeNode).getLastArgument().getALocalSource() + } + + DataFlow::Node getCookieFlagValue(string flag) { + result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() + } + + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + override predicate isInsecure() { + not exists(DataFlow::SourceNode cookieOptions | + cookieOptions = this.getCookieOptionsArgument() and + getCookieFlagValue(flag()).mayHaveBooleanValue(true) + ) + } + } + + /** + * A cookie set using `Set-Cookie` header of an `HTTP` response (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie). + */ + class InsecureSetCookieHeader extends InsecureCookies { + InsecureSetCookieHeader() { + this.asExpr() = any(HTTP::SetCookieHeader setCookie).getHeaderArgument() + } + + override string getKind() { result = "set-cookie header" } + + override DataFlow::Node getCookieOptionsArgument() { + result.asExpr() = this.asExpr().(ArrayExpr).getAnElement() + } + + // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. + override predicate isInsecure() { + not exists(string s | + getCookieOptionsArgument().mayHaveStringValue(s) and + s.matches("%; secure%") + ) + } + } + + /** + * A cookie set using `js-cookie` library (https://github.com/js-cookie/js-cookie). + */ + class InsecureJsCookie extends InsecureCookies { + InsecureJsCookie() { + this = DataFlow::globalVarRef("Cookie").getAMemberCall("set") or + this = DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict").getAMemberCall("set") or + this = DataFlow::moduleMember("js-cookie", "set").getACall() + } + + override string getKind() { result = "js-cookie" } + + override DataFlow::SourceNode getCookieOptionsArgument() { + result = this.(DataFlow::CallNode).getArgument(2).getALocalSource() + } + + DataFlow::Node getCookieFlagValue(string flag) { + result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() + } + + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + override predicate isInsecure() { + not exists(DataFlow::SourceNode cookieOptions | + cookieOptions = this.getCookieOptionsArgument() and + getCookieFlagValue(flag()).mayHaveBooleanValue(true) + ) + } + } +} diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js b/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js new file mode 100644 index 00000000000..009ef60fde3 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js @@ -0,0 +1,17 @@ +const session = require('cookie-session') +const express = require('express') +const app = express() + +const expiryDate = new Date(Date.now() + 60 * 60 * 1000) + +app.use(session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: false, // BAD + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate + } +})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js new file mode 100644 index 00000000000..b16458d2edf --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js @@ -0,0 +1,17 @@ +const session = require('cookie-session') +const express = require('express') +const app = express() + +const expiryDate = new Date(Date.now() + 60 * 60 * 1000) + +app.use(session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: true, // GOOD: false by default for HTTP, true by default for HTTPS + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate + } +})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js new file mode 100644 index 00000000000..02868dee748 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js @@ -0,0 +1,7 @@ +const app = express() +const session = require('express-session') + +app.use(session({ + secret: 'secret', + cookie: { secure: false } // BAD +})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js new file mode 100644 index 00000000000..d7b1841b542 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js @@ -0,0 +1,7 @@ +const app = express() +const session = require('express-session') + +app.use(session({ + secret: 'secret' + // BAD: in this case the default value of `secure` flag is `false` +})) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js new file mode 100644 index 00000000000..0ec001ec4fb --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js @@ -0,0 +1,7 @@ +const app = express() +const session = require('express-session') + +app.use(session({ + secret: 'secret', + cookie: {} // BAD: in this case the default value of `secure` flag is `false` +})) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js new file mode 100644 index 00000000000..0b0f5cd328d --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js @@ -0,0 +1,9 @@ +const app = express() +const session = require('express-session') + +const sess = { + secret: 'secret', + cookie: { secure: false } // BAD +} + +app.use(session(sess)) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js new file mode 100644 index 00000000000..ae2a7f41f55 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js @@ -0,0 +1,9 @@ +const app = express() +const session = require('express-session') + +app.set('trust proxy', 1) + +app.use(session({ + secret: 'secret', + cookie: { secure: true } // GOOD +})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js new file mode 100644 index 00000000000..1a762c27a2c --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js @@ -0,0 +1,12 @@ +const express = require('express') +const app = express() + +app.get('/', function (req, res, next) { + res.cookie('name', 'value', + { + maxAge: 9000000000, + httpOnly: true, + secure: false // BAD + }); + res.end('ok') +}) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js new file mode 100644 index 00000000000..ba67049f167 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js @@ -0,0 +1,12 @@ +const express = require('express') +const app = express() + +app.get('/', function (req, res, next) { + let options = { + maxAge: 9000000000, + httpOnly: true, + secure: false // BAD + } + res.cookie('name', 'value', options); + res.end('ok') +}) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js new file mode 100644 index 00000000000..ee5fe440b93 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js @@ -0,0 +1,12 @@ +const express = require('express') +const app = express() + +app.get('/', function (req, res, next) { + res.cookie('name', 'value', + { + maxAge: 9000000000, + httpOnly: true, + secure: true // GOOD + }); + res.end('ok') +}) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js b/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js new file mode 100644 index 00000000000..dfd2c4bb409 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js @@ -0,0 +1,8 @@ +const http = require('http'); +const server = http.createServer((req, res) => { + res.setHeader('Content-Type', 'text/html'); + // BAD + res.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('ok'); +}); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js new file mode 100644 index 00000000000..8f607aaf972 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js @@ -0,0 +1,8 @@ +const http = require('http'); +const server = http.createServer((req, res) => { + res.setHeader('Content-Type', 'text/html'); + // GOOD + res.setHeader("Set-Cookie", ["type=ninja; Secure", "language=javascript; secure"]); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('ok'); +}); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js b/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js new file mode 100644 index 00000000000..6ab10c64e26 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js @@ -0,0 +1,2 @@ +const js_cookie = require('js-cookie') +js_cookie.set('key', 'value', { secure: false }); // BAD diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js new file mode 100644 index 00000000000..b18c476b2f5 --- /dev/null +++ b/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js @@ -0,0 +1,2 @@ +const js_cookie = require('js-cookie') +js_cookie.set('key', 'value', { secure: true }); From 2cec8f7e9d5a4914f0e83a289fbee963ad89c4c2 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 26 Jul 2020 23:23:56 +0200 Subject: [PATCH 010/146] Update .qhelp --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp index cff9e878e59..d967a59ce97 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -8,7 +8,7 @@ This makes it easier for an attacker to intercept.

    -

    Always set the secure flag to `true` on a cookie before adding it +

    Always set the `secure` flag to `true` on a cookie before adding it to an HTTP response (if the default value is `false`).

    From ac7c511d86f5da9c4ab97a9b7a8094c23c140be1 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 26 Jul 2020 23:47:53 +0200 Subject: [PATCH 011/146] Update .qhelp --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp index d967a59ce97..c8875967298 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -8,7 +8,7 @@ This makes it easier for an attacker to intercept.

    -

    Always set the `secure` flag to `true` on a cookie before adding it +

    Always set the secure flag to `true` on a cookie before adding it to an HTTP response (if the default value is `false`).

    From 8dee3da4fee2d45d22d7f9e570c09132bc059bc9 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 26 Jul 2020 23:50:22 +0200 Subject: [PATCH 012/146] Update .qhelp --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp index c8875967298..cff9e878e59 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -8,7 +8,7 @@ This makes it easier for an attacker to intercept.

    -

    Always set the secure flag to `true` on a cookie before adding it +

    Always set the secure flag to `true` on a cookie before adding it to an HTTP response (if the default value is `false`).

    From 99c95246396071b898f9fd746c45643255d657d8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 11 Aug 2020 13:09:27 +0200 Subject: [PATCH 013/146] Java: Make XssSink extensible. --- java/ql/src/Security/CWE/CWE-079/XSS.ql | 7 +++--- java/ql/src/Security/CWE/CWE-079/XSSLocal.ql | 7 +++--- .../CWE/CWE-209/StackTraceExposure.ql | 6 ++--- java/ql/src/semmle/code/java/security/XSS.qll | 23 +++++++++++-------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql index 009c8fa6935..1a1996c5c16 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql @@ -12,11 +12,10 @@ import java import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking2 import semmle.code.java.security.XSS -import DataFlow2::PathGraph +import DataFlow::PathGraph -class XSSConfig extends TaintTracking2::Configuration { +class XSSConfig extends TaintTracking::Configuration { XSSConfig() { this = "XSSConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } @@ -28,7 +27,7 @@ class XSSConfig extends TaintTracking2::Configuration { } } -from DataFlow2::PathNode source, DataFlow2::PathNode sink, XSSConfig conf +from DataFlow::PathNode source, DataFlow::PathNode sink, XSSConfig conf where conf.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql b/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql index 3c6691986e1..a11a3ade0fd 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSSLocal.ql @@ -12,11 +12,10 @@ import java import semmle.code.java.dataflow.FlowSources -import semmle.code.java.dataflow.TaintTracking2 import semmle.code.java.security.XSS -import DataFlow2::PathGraph +import DataFlow::PathGraph -class XSSLocalConfig extends TaintTracking2::Configuration { +class XSSLocalConfig extends TaintTracking::Configuration { XSSLocalConfig() { this = "XSSLocalConfig" } override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput } @@ -24,7 +23,7 @@ class XSSLocalConfig extends TaintTracking2::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } } -from DataFlow2::PathNode source, DataFlow2::PathNode sink, XSSLocalConfig conf +from DataFlow::PathNode source, DataFlow::PathNode sink, XSSLocalConfig conf where conf.hasFlowPath(source, sink) select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to $@.", source.getNode(), "user-provided value" diff --git a/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql b/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql index bfb0ae0ad59..c9c1e2917c0 100644 --- a/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql +++ b/java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql @@ -14,7 +14,7 @@ import java import semmle.code.java.dataflow.DataFlow -import semmle.code.java.dataflow.TaintTracking2 +import semmle.code.java.dataflow.TaintTracking import semmle.code.java.security.XSS /** @@ -84,7 +84,7 @@ predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) { ) } -class StackTraceStringToXssSinkFlowConfig extends TaintTracking2::Configuration { +class StackTraceStringToXssSinkFlowConfig extends TaintTracking::Configuration { StackTraceStringToXssSinkFlowConfig() { this = "StackTraceExposure::StackTraceStringToXssSinkFlowConfig" } @@ -124,7 +124,7 @@ class GetMessageFlowSource extends MethodAccess { } } -class GetMessageFlowSourceToXssSinkFlowConfig extends TaintTracking2::Configuration { +class GetMessageFlowSourceToXssSinkFlowConfig extends TaintTracking::Configuration { GetMessageFlowSourceToXssSinkFlowConfig() { this = "StackTraceExposure::GetMessageFlowSourceToXssSinkFlowConfig" } diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 9f5ed3fe9d6..84f06f7b41d 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -3,33 +3,36 @@ import semmle.code.java.frameworks.Servlets import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.spring.SpringController import semmle.code.java.frameworks.spring.SpringHttp -import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.TaintTracking2 /* * Definitions for XSS sinks */ -class XssSink extends DataFlow::ExprNode { - XssSink() { +abstract class XssSink extends DataFlow::Node { } + +private class DefaultXssSink extends XssSink { + DefaultXssSink() { exists(HttpServletResponseSendErrorMethod m, MethodAccess ma | ma.getMethod() = m and - this.getExpr() = ma.getArgument(1) + this.asExpr() = ma.getArgument(1) ) or exists(ServletWriterSourceToWritingMethodFlowConfig writer, MethodAccess ma | ma.getMethod() instanceof WritingMethod and writer.hasFlowToExpr(ma.getQualifier()) and - this.getExpr() = ma.getArgument(_) + this.asExpr() = ma.getArgument(_) ) or exists(Method m | m.getDeclaringType() instanceof TypeWebView and ( - m.getAReference().getArgument(0) = this.getExpr() and m.getName() = "loadData" + m.getAReference().getArgument(0) = this.asExpr() and m.getName() = "loadData" or - m.getAReference().getArgument(0) = this.getExpr() and m.getName() = "loadUrl" + m.getAReference().getArgument(0) = this.asExpr() and m.getName() = "loadUrl" or - m.getAReference().getArgument(1) = this.getExpr() and m.getName() = "loadDataWithBaseURL" + m.getAReference().getArgument(1) = this.asExpr() and m.getName() = "loadDataWithBaseURL" ) ) or @@ -77,7 +80,7 @@ class XssSink extends DataFlow::ExprNode { } } -class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking::Configuration { +private class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration { ServletWriterSourceToWritingMethodFlowConfig() { this = "XSS::ServletWriterSourceToWritingMethodFlowConfig" } @@ -91,7 +94,7 @@ class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking::Config } } -class WritingMethod extends Method { +private class WritingMethod extends Method { WritingMethod() { getDeclaringType().getASupertype*().hasQualifiedName("java.io", _) and ( From ba2d19c70f6bb60b0a0e446460149c8667800c98 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 11:46:21 +0200 Subject: [PATCH 014/146] upgrade ts version in package.json --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index c8bee62fba8..e66383a5ef3 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "3.9.2" + "typescript": "4.0.1-rc" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 19d96a56650..0fcb30d02f2 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -225,9 +225,9 @@ tsutils@^2.12.1: dependencies: tslib "^1.8.1" -typescript@3.9.2: - version "3.9.2" - resolved typescript-3.9.2.tgz#64e9c8e9be6ea583c54607677dd4680a1cf35db9 +typescript@4.0.1-rc: + version "4.0.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.1-rc.tgz#8adc78223eae56fe71d906a5fa90c3543b07a677" wrappy@1: version "1.0.2" From 08c017eb0909b5fd612a3ae5e9b370c16f9ca2e0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 10:17:28 +0200 Subject: [PATCH 015/146] change where tuples elements are loaded from to match TS 4.0 --- .../src/com/semmle/js/parser/TypeScriptASTConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 4a57871c871..8331d91326e 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -2177,7 +2177,7 @@ public class TypeScriptASTConverter { } private Node convertTupleType(JsonObject node, SourceLocation loc) throws ParseError { - return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elementTypes")); + return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements")); } private Node convertTypeAliasDeclaration(JsonObject node, SourceLocation loc) throws ParseError { From b602a36a24198473c1e8222389f48721f7f598a8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 10:18:06 +0200 Subject: [PATCH 016/146] add test for generic spreads in a tuple --- .../TypeScript/TypeAnnotations/tests.expected | 4 ++++ .../test/library-tests/TypeScript/TypeAnnotations/tst.ts | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 5db52c2afcd..0e0d34153e7 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -108,6 +108,7 @@ test_VariableTypes | tst.ts:142:17:142:25 | condition | condition | tst.ts:142:28:142:30 | any | | tst.ts:142:33:142:35 | msg | msg | tst.ts:142:39:142:44 | string | | tst.ts:148:25:148:27 | val | val | tst.ts:148:30:148:32 | any | +| tst.ts:157:32:157:34 | arr | arr | tst.ts:157:37:157:56 | readonly [any, ...T] | test_QualifiedTypeAccess | tst.ts:63:19:63:21 | N.I | tst.ts:63:19:63:19 | N | tst.ts:63:21:63:21 | I | | tst.ts:64:20:64:24 | N.M.I | tst.ts:64:20:64:22 | N.M | tst.ts:64:24:64:24 | I | @@ -198,6 +199,8 @@ test_TupleTypeExpr | tst.ts:136:39:136:68 | [number ... mber[]] | 0 | 3 | tst.ts:136:40:136:45 | number | | tst.ts:136:39:136:68 | [number ... mber[]] | 1 | 3 | tst.ts:136:48:136:54 | string? | | tst.ts:136:39:136:68 | [number ... mber[]] | 2 | 3 | tst.ts:136:57:136:67 | ...number[] | +| tst.ts:157:46:157:56 | [any, ...T] | 0 | 2 | tst.ts:157:47:157:49 | any | +| tst.ts:157:46:157:56 | [any, ...T] | 1 | 2 | tst.ts:157:52:157:55 | ...T | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | @@ -219,6 +222,7 @@ test_ArrayTypeExpr | tst.ts:81:27:81:34 | string[] | tst.ts:81:27:81:32 | string | | tst.ts:135:39:135:46 | string[] | tst.ts:135:39:135:44 | string | | tst.ts:136:60:136:67 | number[] | tst.ts:136:60:136:65 | number | +| tst.ts:157:25:157:29 | any[] | tst.ts:157:25:157:27 | any | test_TypeAccessHelpers | tst.ts:65:18:65:24 | Generic | 1 | 0 | tst.ts:65:26:65:31 | number | | tst.ts:66:18:66:32 | N.InnerGeneric1 | 1 | 0 | tst.ts:66:34:66:39 | number | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts index faeb9e9c833..975432f4576 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts @@ -150,3 +150,11 @@ function assertIsString(val: any): asserts val is string { throw new AssertionError("Not a string!"); } } + +// TypeScript 4.0 + +// spreads in tuple type syntax can now be generic +function tail(arr: readonly [any, ...T]) { + const [_ignored, ...rest] = arr; + return rest; +} \ No newline at end of file From 2612e0c5dd8acec40f65b4297a0efd8932a9cba5 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 10:19:27 +0200 Subject: [PATCH 017/146] add test for spread in tuple in non-last position --- .../library-tests/TypeScript/TypeAnnotations/tests.expected | 6 ++++++ .../ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 0e0d34153e7..9e3733d8480 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -109,6 +109,8 @@ test_VariableTypes | tst.ts:142:33:142:35 | msg | msg | tst.ts:142:39:142:44 | string | | tst.ts:148:25:148:27 | val | val | tst.ts:148:30:148:32 | any | | tst.ts:157:32:157:34 | arr | arr | tst.ts:157:37:157:56 | readonly [any, ...T] | +| tst.ts:164:47:164:50 | arr1 | arr1 | tst.ts:164:53:164:53 | T | +| tst.ts:164:56:164:59 | arr2 | arr2 | tst.ts:164:62:164:62 | U | test_QualifiedTypeAccess | tst.ts:63:19:63:21 | N.I | tst.ts:63:19:63:19 | N | tst.ts:63:21:63:21 | I | | tst.ts:64:20:64:24 | N.M.I | tst.ts:64:20:64:22 | N.M | tst.ts:64:24:64:24 | I | @@ -201,6 +203,8 @@ test_TupleTypeExpr | tst.ts:136:39:136:68 | [number ... mber[]] | 2 | 3 | tst.ts:136:57:136:67 | ...number[] | | tst.ts:157:46:157:56 | [any, ...T] | 0 | 2 | tst.ts:157:47:157:49 | any | | tst.ts:157:46:157:56 | [any, ...T] | 1 | 2 | tst.ts:157:52:157:55 | ...T | +| tst.ts:164:66:164:77 | [...T, ...U] | 0 | 2 | tst.ts:164:67:164:70 | ...T | +| tst.ts:164:66:164:77 | [...T, ...U] | 1 | 2 | tst.ts:164:73:164:76 | ...U | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | @@ -223,6 +227,7 @@ test_ArrayTypeExpr | tst.ts:135:39:135:46 | string[] | tst.ts:135:39:135:44 | string | | tst.ts:136:60:136:67 | number[] | tst.ts:136:60:136:65 | number | | tst.ts:157:25:157:29 | any[] | tst.ts:157:25:157:27 | any | +| tst.ts:163:21:163:25 | any[] | tst.ts:163:21:163:23 | any | test_TypeAccessHelpers | tst.ts:65:18:65:24 | Generic | 1 | 0 | tst.ts:65:26:65:31 | number | | tst.ts:66:18:66:32 | N.InnerGeneric1 | 1 | 0 | tst.ts:66:34:66:39 | number | @@ -274,6 +279,7 @@ test_ReturnTypes | tst.ts:96:1:96:52 | functio ... rn x; } | function f3 | tst.ts:96:38:96:38 | S | | tst.ts:142:1:146:1 | functio ... )\\n }\\n} | function assert | tst.ts:142:48:142:64 | asserts condition | | tst.ts:148:1:152:1 | functio ... ;\\n }\\n} | function assertIsString | tst.ts:148:36:148:56 | asserts ... string | +| tst.ts:164:1:166:1 | functio ... rr2];\\n} | function concat | tst.ts:164:66:164:77 | [...T, ...U] | test_KeyofTypeExpr | tst.ts:49:16:49:30 | keyof Interface | tst.ts:49:22:49:30 | Interface | | tst.ts:113:26:113:35 | keyof Node | tst.ts:113:32:113:35 | Node | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts index 975432f4576..fb9539e35e8 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts @@ -157,4 +157,10 @@ function assertIsString(val: any): asserts val is string { function tail(arr: readonly [any, ...T]) { const [_ignored, ...rest] = arr; return rest; +} + +// spread in tuple in non-last position +type Arr = readonly any[]; +function concat(arr1: T, arr2: U): [...T, ...U] { + return [...arr1, ...arr2]; } \ No newline at end of file From ea583fe86242e6e676d83c59e659296aef489171 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 11:47:28 +0200 Subject: [PATCH 018/146] add basic support for named tuple elements --- .../src/com/semmle/js/parser/TypeScriptASTConverter.java | 6 ++++++ .../library-tests/TypeScript/TypeAnnotations/tests.expected | 4 ++++ .../ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 8331d91326e..e4d60d2b0f7 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -585,6 +585,8 @@ public class TypeScriptASTConverter { return convertTryStatement(node, loc); case "TupleType": return convertTupleType(node, loc); + case "NamedTupleMember": + return convertNamedTupleMember(node, loc); case "TypeAliasDeclaration": return convertTypeAliasDeclaration(node, loc); case "TypeAssertionExpression": @@ -2180,6 +2182,10 @@ public class TypeScriptASTConverter { return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements")); } + private Node convertNamedTupleMember(JsonObject node, SourceLocation loc) throws ParseError { + return convertChild(node, "type"); + } + private Node convertTypeAliasDeclaration(JsonObject node, SourceLocation loc) throws ParseError { TypeAliasDeclaration typeAlias = new TypeAliasDeclaration( diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 9e3733d8480..f7eda7865e7 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -111,6 +111,7 @@ test_VariableTypes | tst.ts:157:32:157:34 | arr | arr | tst.ts:157:37:157:56 | readonly [any, ...T] | | tst.ts:164:47:164:50 | arr1 | arr1 | tst.ts:164:53:164:53 | T | | tst.ts:164:56:164:59 | arr2 | arr2 | tst.ts:164:62:164:62 | U | +| tst.ts:169:31:169:31 | x | x | tst.ts:169:34:169:64 | [first: ... number] | test_QualifiedTypeAccess | tst.ts:63:19:63:21 | N.I | tst.ts:63:19:63:19 | N | tst.ts:63:21:63:21 | I | | tst.ts:64:20:64:24 | N.M.I | tst.ts:64:20:64:22 | N.M | tst.ts:64:24:64:24 | I | @@ -205,6 +206,8 @@ test_TupleTypeExpr | tst.ts:157:46:157:56 | [any, ...T] | 1 | 2 | tst.ts:157:52:157:55 | ...T | | tst.ts:164:66:164:77 | [...T, ...U] | 0 | 2 | tst.ts:164:67:164:70 | ...T | | tst.ts:164:66:164:77 | [...T, ...U] | 1 | 2 | tst.ts:164:73:164:76 | ...U | +| tst.ts:169:34:169:64 | [first: ... number] | 0 | 2 | tst.ts:169:42:169:47 | number | +| tst.ts:169:34:169:64 | [first: ... number] | 1 | 2 | tst.ts:169:58:169:63 | number | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | @@ -280,6 +283,7 @@ test_ReturnTypes | tst.ts:142:1:146:1 | functio ... )\\n }\\n} | function assert | tst.ts:142:48:142:64 | asserts condition | | tst.ts:148:1:152:1 | functio ... ;\\n }\\n} | function assertIsString | tst.ts:148:36:148:56 | asserts ... string | | tst.ts:164:1:166:1 | functio ... rr2];\\n} | function concat | tst.ts:164:66:164:77 | [...T, ...U] | +| tst.ts:169:1:172:1 | functio ... + b;\\n} | function labelOnTupleElements | tst.ts:169:68:169:73 | number | test_KeyofTypeExpr | tst.ts:49:16:49:30 | keyof Interface | tst.ts:49:22:49:30 | Interface | | tst.ts:113:26:113:35 | keyof Node | tst.ts:113:32:113:35 | Node | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts index fb9539e35e8..d5b02b4911b 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts @@ -163,4 +163,10 @@ function tail(arr: readonly [any, ...T]) { type Arr = readonly any[]; function concat(arr1: T, arr2: U): [...T, ...U] { return [...arr1, ...arr2]; +} + +// labelled tuple elements +function labelOnTupleElements(x: [first: number, second: number]): number { + let [a, b] = x; + return a + b; } \ No newline at end of file From 2f34990ae6ae700a033847ac2ba20519b36d597f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 11:49:39 +0200 Subject: [PATCH 019/146] add another test for spread elements in tuple types --- .../TypeScript/TypeAnnotations/tests.expected | 7 +++++++ .../library-tests/TypeScript/TypeAnnotations/tst.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index f7eda7865e7..23cd84a8b55 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -112,6 +112,7 @@ test_VariableTypes | tst.ts:164:47:164:50 | arr1 | arr1 | tst.ts:164:53:164:53 | T | | tst.ts:164:56:164:59 | arr2 | arr2 | tst.ts:164:62:164:62 | U | | tst.ts:169:31:169:31 | x | x | tst.ts:169:34:169:64 | [first: ... number] | +| tst.ts:180:5:180:7 | foo | foo | tst.ts:180:10:180:21 | StrStrNumNum | test_QualifiedTypeAccess | tst.ts:63:19:63:21 | N.I | tst.ts:63:19:63:19 | N | tst.ts:63:21:63:21 | I | | tst.ts:64:20:64:24 | N.M.I | tst.ts:64:20:64:22 | N.M | tst.ts:64:24:64:24 | I | @@ -208,6 +209,12 @@ test_TupleTypeExpr | tst.ts:164:66:164:77 | [...T, ...U] | 1 | 2 | tst.ts:164:73:164:76 | ...U | | tst.ts:169:34:169:64 | [first: ... number] | 0 | 2 | tst.ts:169:42:169:47 | number | | tst.ts:169:34:169:64 | [first: ... number] | 1 | 2 | tst.ts:169:58:169:63 | number | +| tst.ts:175:16:175:31 | [string, string] | 0 | 2 | tst.ts:175:17:175:22 | string | +| tst.ts:175:16:175:31 | [string, string] | 1 | 2 | tst.ts:175:25:175:30 | string | +| tst.ts:176:16:176:31 | [number, number] | 0 | 2 | tst.ts:176:17:176:22 | number | +| tst.ts:176:16:176:31 | [number, number] | 1 | 2 | tst.ts:176:25:176:30 | number | +| tst.ts:179:21:179:44 | [...Str ... umbers] | 0 | 2 | tst.ts:179:22:179:31 | ...Strings | +| tst.ts:179:21:179:44 | [...Str ... umbers] | 1 | 2 | tst.ts:179:34:179:43 | ...Numbers | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts index d5b02b4911b..4b4ec925f08 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts @@ -169,4 +169,12 @@ function concat(arr1: T, arr2: U): [...T, ...U] { function labelOnTupleElements(x: [first: number, second: number]): number { let [a, b] = x; return a + b; -} \ No newline at end of file +} + +// spread elements can occur anywhere in a tuple – not just at the end! +type Strings = [string, string]; +type Numbers = [number, number]; + +// [string, string, number, number] +type StrStrNumNum = [...Strings, ...Numbers]; +var foo: StrStrNumNum; \ No newline at end of file From d2c87d0a2ee5c5079be78a26c1cbd6e43f27efde Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 11 Aug 2020 13:55:01 +0200 Subject: [PATCH 020/146] add support for the new assign expression in TypeScript 4 --- .../com/semmle/js/extractor/ExprKinds.java | 3 ++ javascript/ql/src/semmle/javascript/Expr.qll | 35 ++++++++++++++++++- .../ql/src/semmlecode.javascript.dbscheme | 5 ++- .../TypeScript/TypeAnnotations/tests.expected | 3 ++ .../TypeScript/TypeAnnotations/tst.ts | 11 +++++- 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java b/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java index d88f341bc0e..c470d1df804 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ExprKinds.java @@ -77,6 +77,9 @@ public class ExprKinds { binOpKinds.put("**", 87); binOpKinds.put("**=", 88); binOpKinds.put("??", 107); + binOpKinds.put("&&=", 116); + binOpKinds.put("||=", 117); + binOpKinds.put("??=", 118); } private static final Map unOpKinds = new LinkedHashMap(); diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index cba8be4241f..2aefcd2ffd9 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -1851,7 +1851,7 @@ class AssignExpr extends @assignexpr, Assignment { private class TCompoundAssignExpr = @assignaddexpr or @assignsubexpr or @assignmulexpr or @assigndivexpr or @assignmodexpr or @assignexpexpr or @assignlshiftexpr or @assignrshiftexpr or @assignurshiftexpr or - @assignorexpr or @assignxorexpr or @assignandexpr; + @assignorexpr or @assignxorexpr or @assignandexpr or @assignlogandexpr or @assignlogorexpr or @assignnullishcoalescingexpr; /** * A compound assign expression. @@ -1997,6 +1997,39 @@ class AssignXOrExpr extends @assignxorexpr, CompoundAssignExpr { } */ class AssignAndExpr extends @assignandexpr, CompoundAssignExpr { } +/** + * A logical-'or'-assign expression. + * + * Example: + * + * ``` + * x ||= y + * ``` + */ +class AssignLogOrExpr extends @assignlogandexpr, CompoundAssignExpr { } + +/** + * A logical-'and'-assign expression. + * + * Example: + * + * ``` + * x &&= y + * ``` + */ +class AssignLogAndExpr extends @assignlogorexpr, CompoundAssignExpr { } + +/** + * A 'nullish-coalescing'-assign expression. + * + * Example: + * + * ``` + * x ??= y + * ``` + */ +class AssignNullishCoalescingExpr extends @assignnullishcoalescingexpr, CompoundAssignExpr { } + /** * An update expression, that is, an increment or decrement expression. * diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index 2dc7a038982..c73fbfca57f 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -351,6 +351,9 @@ case @expr.kind of | 113 = @e4x_xml_dynamic_qualident | 114 = @e4x_xml_dotdotexpr | 115 = @importmetaexpr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr ; @varaccess = @proper_varaccess | @export_varaccess; @@ -372,7 +375,7 @@ case @expr.kind of @binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; -@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; @updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 23cd84a8b55..08738d8786f 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -113,6 +113,9 @@ test_VariableTypes | tst.ts:164:56:164:59 | arr2 | arr2 | tst.ts:164:62:164:62 | U | | tst.ts:169:31:169:31 | x | x | tst.ts:169:34:169:64 | [first: ... number] | | tst.ts:180:5:180:7 | foo | foo | tst.ts:180:10:180:21 | StrStrNumNum | +| tst.ts:184:7:184:8 | a1 | a1 | tst.ts:184:12:184:17 | number | +| tst.ts:185:7:185:8 | a2 | a2 | tst.ts:185:12:185:17 | number | +| tst.ts:186:7:186:8 | a3 | a3 | tst.ts:186:12:186:17 | number | test_QualifiedTypeAccess | tst.ts:63:19:63:21 | N.I | tst.ts:63:19:63:19 | N | tst.ts:63:21:63:21 | I | | tst.ts:64:20:64:24 | N.M.I | tst.ts:64:20:64:22 | N.M | tst.ts:64:24:64:24 | I | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts index 4b4ec925f08..138576c4b4f 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts @@ -177,4 +177,13 @@ type Numbers = [number, number]; // [string, string, number, number] type StrStrNumNum = [...Strings, ...Numbers]; -var foo: StrStrNumNum; \ No newline at end of file +var foo: StrStrNumNum; + +// Short-Circuiting Assignment Operators +function shortAssignment() { + let a1 : number = parseInt("foo"); + let a2 : number = parseInt("bar"); + let a3 : number = a1 ||= a2; + let a4 = a2 &&= a3; + let a5 = a3 ??= a4; +} \ No newline at end of file From b10130524806768455bfd8d23cceb54e850426b4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 12 Aug 2020 09:27:43 +0200 Subject: [PATCH 021/146] autoformat --- javascript/ql/src/semmle/javascript/Expr.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index 2aefcd2ffd9..53546033e87 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -1851,7 +1851,8 @@ class AssignExpr extends @assignexpr, Assignment { private class TCompoundAssignExpr = @assignaddexpr or @assignsubexpr or @assignmulexpr or @assigndivexpr or @assignmodexpr or @assignexpexpr or @assignlshiftexpr or @assignrshiftexpr or @assignurshiftexpr or - @assignorexpr or @assignxorexpr or @assignandexpr or @assignlogandexpr or @assignlogorexpr or @assignnullishcoalescingexpr; + @assignorexpr or @assignxorexpr or @assignandexpr or @assignlogandexpr or @assignlogorexpr or + @assignnullishcoalescingexpr; /** * A compound assign expression. From 211ef610399a253512246e5574d3f2e34f9255be Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 12 Aug 2020 09:29:34 +0200 Subject: [PATCH 022/146] add change note --- change-notes/1.25/analysis-javascript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.25/analysis-javascript.md b/change-notes/1.25/analysis-javascript.md index 33d9055b839..9491ecb657f 100644 --- a/change-notes/1.25/analysis-javascript.md +++ b/change-notes/1.25/analysis-javascript.md @@ -30,7 +30,7 @@ - [yargs](https://www.npmjs.com/package/yargs) - [webpack-dev-server](https://www.npmjs.com/package/webpack-dev-server) -* TypeScript 3.9 is now supported. +* TypeScript 4.0 is now supported. * TypeScript code embedded in HTML and Vue files is now extracted and analyzed. From 26dcd2faaedf19936be62428912d82920f0b0ec4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 12 Aug 2020 10:33:49 +0200 Subject: [PATCH 023/146] add support for getting the name from named tuple elements --- .../src/com/semmle/js/ast/NodeCopier.java | 2 +- .../com/semmle/js/extractor/ASTExtractor.java | 5 +++++ .../js/parser/TypeScriptASTConverter.java | 18 +++++++++++++++++- .../src/com/semmle/ts/ast/TupleTypeExpr.java | 8 +++++++- .../ql/src/semmle/javascript/TypeScript.qll | 3 +++ .../ql/src/semmlecode.javascript.dbscheme | 7 +++++++ .../TypeAnnotations/TupleTypeExpr.qll | 4 ++++ .../TypeScript/TypeAnnotations/tests.expected | 3 +++ 8 files changed, 47 insertions(+), 3 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java b/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java index 18a3e55b8c9..ddf57b32cff 100644 --- a/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java +++ b/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java @@ -705,7 +705,7 @@ public class NodeCopier implements Visitor { @Override public INode visit(TupleTypeExpr nd, Void c) { - return new TupleTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes())); + return new TupleTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()), nd.getElementNames()); } @Override diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 8dcc6d3a5c5..4bf57075b0b 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -1819,6 +1819,11 @@ public class ASTExtractor { @Override public Label visit(TupleTypeExpr nd, Context c) { Label key = super.visit(nd, c); + if (nd.getElementNames() != null) { + for (int i = 0; i < nd.getElementNames().size(); i++) { + trapwriter.addTuple("tuple_element_name", key, i, nd.getElementNames().get(i)); + } + } visitAll(nd.getElementTypes(), key, IdContext.typeBind, 0); return key; } diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index e4d60d2b0f7..83529f8b1b4 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -2179,9 +2180,24 @@ public class TypeScriptASTConverter { } private Node convertTupleType(JsonObject node, SourceLocation loc) throws ParseError { - return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements")); + List elements = new ArrayList<>(); + ((JsonArray)node.get("elements")).iterator().forEachRemaining(elements::add); + + List elementNames = elements.stream() + .filter(n -> getKind(n).equals("NamedTupleMember")) + .map(n -> n.getAsJsonObject().get("name")) + .map(n -> n.getAsJsonObject().get("escapedText")) + .map(n -> n.getAsString()) + .collect(Collectors.toList()); + + if (elementNames.size() == 0) { + elementNames = null; + } + + return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements"), elementNames); } + // This method just does a trivial forward to the type. The names have already been extracted in `convertTupleType`. private Node convertNamedTupleMember(JsonObject node, SourceLocation loc) throws ParseError { return convertChild(node, "type"); } diff --git a/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java index 5b9044cd63f..9d49899fafd 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java @@ -7,16 +7,22 @@ import java.util.List; /** A tuple type, such as [number, string]. */ public class TupleTypeExpr extends TypeExpression { private final List elementTypes; + private final List elementNames; - public TupleTypeExpr(SourceLocation loc, List elementTypes) { + public TupleTypeExpr(SourceLocation loc, List elementTypes, List elementNames) { super("TupleTypeExpr", loc); this.elementTypes = elementTypes; + this.elementNames = elementNames; } public List getElementTypes() { return elementTypes; } + public List getElementNames() { + return elementNames; + } + @Override public R accept(Visitor v, C c) { return v.visit(this, c); diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 72536ea5db4..82088638a60 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -853,6 +853,9 @@ class TupleTypeExpr extends @tupletypeexpr, TypeExpr { /** Gets the number of elements in the tuple type. */ int getNumElementType() { result = count(getAnElementType()) } + + /** Gets the name of the `n`th tuple member if the tuple members are named. */ + string getElementName(int n) { tuple_element_name(this, n, result) } } /** diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index c73fbfca57f..3f291931cb8 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -790,6 +790,13 @@ tuple_type_rest( unique int typ: @type ref ); +#keyset[tuple, index] +tuple_element_name ( + int tuple: @tupletypeexpr ref, + int index: int ref, + varchar(900) name: string ref +); + // comments comments (unique int id: @comment, int kind: int ref, diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll index b8cbe0ab2e3..488138a10e4 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll @@ -3,3 +3,7 @@ import javascript query predicate test_TupleTypeExpr(TupleTypeExpr type, int n, int res0, TypeExpr res1) { res0 = type.getNumElementType() and res1 = type.getElementType(n) } + +query predicate test_TupleTypeElementName(TupleTypeExpr type, int n, string name) { + name = type.getElementName(n) +} \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 08738d8786f..00bda23ab3f 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -218,6 +218,9 @@ test_TupleTypeExpr | tst.ts:176:16:176:31 | [number, number] | 1 | 2 | tst.ts:176:25:176:30 | number | | tst.ts:179:21:179:44 | [...Str ... umbers] | 0 | 2 | tst.ts:179:22:179:31 | ...Strings | | tst.ts:179:21:179:44 | [...Str ... umbers] | 1 | 2 | tst.ts:179:34:179:43 | ...Numbers | +test_TupleTypeElementName +| tst.ts:169:34:169:64 | [first: ... number] | 0 | first | +| tst.ts:169:34:169:64 | [first: ... number] | 1 | second | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | From 0e33eae960c71daeee64f064bb770bdd72df0eb8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 12 Aug 2020 10:58:18 +0200 Subject: [PATCH 024/146] add dbscheme upgrade script --- .../TypeAnnotations/TupleTypeExpr.qll | 2 +- .../old.dbscheme | 1190 ++++++++++++++++ .../semmlecode.javascript.dbscheme | 1200 +++++++++++++++++ .../upgrade.properties | 2 + 4 files changed, 2393 insertions(+), 1 deletion(-) create mode 100644 javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/old.dbscheme create mode 100644 javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/upgrade.properties diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll index 488138a10e4..03fe4325786 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll @@ -6,4 +6,4 @@ query predicate test_TupleTypeExpr(TupleTypeExpr type, int n, int res0, TypeExpr query predicate test_TupleTypeElementName(TupleTypeExpr type, int n, string name) { name = type.getElementName(n) -} \ No newline at end of file +} diff --git a/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/old.dbscheme b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/old.dbscheme new file mode 100644 index 00000000000..2dc7a038982 --- /dev/null +++ b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/old.dbscheme @@ -0,0 +1,1190 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int 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); + +/** 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); + +/** External data **/ + +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); + +/** Version control data **/ + +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 +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* 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; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..3f291931cb8 --- /dev/null +++ b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme @@ -0,0 +1,1200 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int 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); + +/** 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); + +/** External data **/ + +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); + +/** Version control data **/ + +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 +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +isExterns (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url; + +isModule (int tl: @toplevel ref); +isNodejs (int tl: @toplevel ref); +isES2015Module (int tl: @toplevel ref); +isClosureModule (int tl: @toplevel ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmtparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmtContainers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jumpTargets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmtparent = @stmt | @toplevel | @functionexpr | @arrowfunctionexpr; +@stmt_container = @toplevel | @function | @namespacedeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration; + +case @stmt.kind of + 0 = @emptystmt +| 1 = @blockstmt +| 2 = @exprstmt +| 3 = @ifstmt +| 4 = @labeledstmt +| 5 = @breakstmt +| 6 = @continuestmt +| 7 = @withstmt +| 8 = @switchstmt +| 9 = @returnstmt +| 10 = @throwstmt +| 11 = @trystmt +| 12 = @whilestmt +| 13 = @dowhilestmt +| 14 = @forstmt +| 15 = @forinstmt +| 16 = @debuggerstmt +| 17 = @functiondeclstmt +| 18 = @vardeclstmt +| 19 = @case +| 20 = @catchclause +| 21 = @forofstmt +| 22 = @constdeclstmt +| 23 = @letstmt +| 24 = @legacy_letstmt +| 25 = @foreachstmt +| 26 = @classdeclstmt +| 27 = @importdeclaration +| 28 = @exportalldeclaration +| 29 = @exportdefaultdeclaration +| 30 = @exportnameddeclaration +| 31 = @namespacedeclaration +| 32 = @importequalsdeclaration +| 33 = @exportassigndeclaration +| 34 = @interfacedeclaration +| 35 = @typealiasdeclaration +| 36 = @enumdeclaration +| 37 = @externalmoduledeclaration +| 38 = @exportasnamespacedeclaration +| 39 = @globalaugmentationdeclaration +; + +@declstmt = @vardeclstmt | @constdeclstmt | @letstmt | @legacy_letstmt; + +@exportdeclaration = @exportalldeclaration | @exportdefaultdeclaration | @exportnameddeclaration; + +@namespacedefinition = @namespacedeclaration | @enumdeclaration; +@typedefinition = @classdefinition | @interfacedeclaration | @enumdeclaration | @typealiasdeclaration | @enum_member; + +isInstantiated(unique int decl: @namespacedeclaration ref); + +@declarablenode = @declstmt | @namespacedeclaration | @classdeclstmt | @functiondeclstmt | @enumdeclaration | @externalmoduledeclaration | @globalaugmentationdeclaration | @field; +hasDeclareKeyword(unique int stmt: @declarablenode ref); + +isForAwaitOf(unique int forof: @forofstmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @exprparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @exprortype ref); + +enclosingStmt (unique int expr: @exprortype ref, + int stmt: @stmt ref); + +exprContainers (unique int expr: @exprortype ref, + int container: @stmt_container ref); + +arraySize (unique int ae: @arraylike ref, + int sz: int ref); + +isDelegating (int yield: @yieldexpr ref); + +@exprorstmt = @expr | @stmt; +@exprortype = @expr | @typeexpr; +@exprparent = @exprorstmt | @property | @functiontypeexpr; +@arraylike = @arrayexpr | @arraypattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @nullliteral +| 2 = @booleanliteral +| 3 = @numberliteral +| 4 = @stringliteral +| 5 = @regexpliteral +| 6 = @thisexpr +| 7 = @arrayexpr +| 8 = @objexpr +| 9 = @functionexpr +| 10 = @seqexpr +| 11 = @conditionalexpr +| 12 = @newexpr +| 13 = @callexpr +| 14 = @dotexpr +| 15 = @indexexpr +| 16 = @negexpr +| 17 = @plusexpr +| 18 = @lognotexpr +| 19 = @bitnotexpr +| 20 = @typeofexpr +| 21 = @voidexpr +| 22 = @deleteexpr +| 23 = @eqexpr +| 24 = @neqexpr +| 25 = @eqqexpr +| 26 = @neqqexpr +| 27 = @ltexpr +| 28 = @leexpr +| 29 = @gtexpr +| 30 = @geexpr +| 31 = @lshiftexpr +| 32 = @rshiftexpr +| 33 = @urshiftexpr +| 34 = @addexpr +| 35 = @subexpr +| 36 = @mulexpr +| 37 = @divexpr +| 38 = @modexpr +| 39 = @bitorexpr +| 40 = @xorexpr +| 41 = @bitandexpr +| 42 = @inexpr +| 43 = @instanceofexpr +| 44 = @logandexpr +| 45 = @logorexpr +| 47 = @assignexpr +| 48 = @assignaddexpr +| 49 = @assignsubexpr +| 50 = @assignmulexpr +| 51 = @assigndivexpr +| 52 = @assignmodexpr +| 53 = @assignlshiftexpr +| 54 = @assignrshiftexpr +| 55 = @assignurshiftexpr +| 56 = @assignorexpr +| 57 = @assignxorexpr +| 58 = @assignandexpr +| 59 = @preincexpr +| 60 = @postincexpr +| 61 = @predecexpr +| 62 = @postdecexpr +| 63 = @parexpr +| 64 = @vardeclarator +| 65 = @arrowfunctionexpr +| 66 = @spreadelement +| 67 = @arraypattern +| 68 = @objectpattern +| 69 = @yieldexpr +| 70 = @taggedtemplateexpr +| 71 = @templateliteral +| 72 = @templateelement +| 73 = @arraycomprehensionexpr +| 74 = @generatorexpr +| 75 = @forincomprehensionblock +| 76 = @forofcomprehensionblock +| 77 = @legacy_letexpr +| 78 = @vardecl +| 79 = @proper_varaccess +| 80 = @classexpr +| 81 = @superexpr +| 82 = @newtargetexpr +| 83 = @namedimportspecifier +| 84 = @importdefaultspecifier +| 85 = @importnamespacespecifier +| 86 = @namedexportspecifier +| 87 = @expexpr +| 88 = @assignexpexpr +| 89 = @jsxelement +| 90 = @jsxqualifiedname +| 91 = @jsxemptyexpr +| 92 = @awaitexpr +| 93 = @functionsentexpr +| 94 = @decorator +| 95 = @exportdefaultspecifier +| 96 = @exportnamespacespecifier +| 97 = @bindexpr +| 98 = @externalmodulereference +| 99 = @dynamicimport +| 100 = @expressionwithtypearguments +| 101 = @prefixtypeassertion +| 102 = @astypeassertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigintliteral +| 107 = @nullishcoalescingexpr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @importmetaexpr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @vardecl | @varaccess; + +@identifier = @label | @varref | @typeidentifier; + +@literal = @nullliteral | @booleanliteral | @numberliteral | @stringliteral | @regexpliteral | @bigintliteral; + +@propaccess = @dotexpr | @indexexpr; + +@invokeexpr = @newexpr | @callexpr; + +@unaryexpr = @negexpr | @plusexpr | @lognotexpr | @bitnotexpr | @typeofexpr | @voidexpr | @deleteexpr | @spreadelement; + +@equalitytest = @eqexpr | @neqexpr | @eqqexpr | @neqqexpr; + +@comparison = @equalitytest | @ltexpr | @leexpr | @gtexpr | @geexpr; + +@binaryexpr = @comparison | @lshiftexpr | @rshiftexpr | @urshiftexpr | @addexpr | @subexpr | @mulexpr | @divexpr | @modexpr | @expexpr | @bitorexpr | @xorexpr | @bitandexpr | @inexpr | @instanceofexpr | @logandexpr | @logorexpr | @nullishcoalescingexpr; + +@assignment = @assignexpr | @assignaddexpr | @assignsubexpr | @assignmulexpr | @assigndivexpr | @assignmodexpr | @assignexpexpr | @assignlshiftexpr | @assignrshiftexpr | @assignurshiftexpr | @assignorexpr | @assignxorexpr | @assignandexpr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preincexpr | @postincexpr | @predecexpr | @postdecexpr; + +@pattern = @varref | @arraypattern | @objectpattern; + +@comprehensionexpr = @arraycomprehensionexpr | @generatorexpr; + +@comprehensionblock = @forincomprehensionblock | @forofcomprehensionblock; + +@importspecifier = @namedimportspecifier | @importdefaultspecifier | @importnamespacespecifier; + +@exportspecifier = @namedexportspecifier | @exportdefaultspecifier | @exportnamespacespecifier; + +@import_or_export_declaration = @importdeclaration | @exportdeclaration; + +@typeassertion = @astypeassertion | @prefixtypeassertion; + +@classdefinition = @classdeclstmt | @classexpr; +@interfacedefinition = @interfacedeclaration | @interfacetypeexpr; +@classorinterface = @classdefinition | @interfacedefinition; + +@lexical_decl = @vardecl | @typedecl; +@lexical_access = @varaccess | @localtypeaccess | @localvartypeaccess | @localnamespaceaccess; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @globalscope +| 1 = @functionscope +| 2 = @catchscope +| 3 = @modulescope +| 4 = @blockscope +| 5 = @forscope +| 6 = @forinscope // for-of scopes work the same as for-in scopes +| 7 = @comprehensionblockscope +| 8 = @classexprscope +| 9 = @namespacescope +| 10 = @classdeclscope +| 11 = @interfacescope +| 12 = @typealiasscope +| 13 = @mappedtypescope +| 14 = @enumscope +| 15 = @externalmodulescope +| 16 = @conditionaltypescope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @functiondeclstmt | @functionexpr | @arrowfunctionexpr; + +@parameterized = @function | @catchclause; +@type_parameterized = @function | @classorinterface | @typealiasdeclaration | @mappedtypeexpr | @infertypeexpr; + +isGenerator (int fun: @function ref); +hasRestParameter (int fun: @function ref); +isAsync (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +isArgumentsObject (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @localvartypeaccess; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @vardecl ref, + int decl: @variable ref); + +@typebind_id = @localtypeaccess | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @typedecl | @vardecl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @vardecl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @localnamespaceaccess | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @objexpr | @objectpattern | @classdefinition | @jsxelement | @interfacedefinition | @enumdeclaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @vardeclarator; + +isComputed (int id: @property ref); +isMethod (int id: @property ref); +isStatic (int id: @property ref); +isAbstractMember (int id: @property ref); +isConstEnum (int id: @enumdeclaration ref); +isAbstractClass (int id: @classdeclstmt ref); + +hasPublicKeyword (int id: @property ref); +hasPrivateKeyword (int id: @property ref); +hasProtectedKeyword (int id: @property ref); +hasReadonlyKeyword (int id: @property ref); +hasTypeKeyword (int id: @import_or_export_declaration ref); +isOptionalMember (int id: @property ref); +hasDefiniteAssignmentAssertion (int id: @field_or_vardeclarator ref); +isOptionalParameterDeclaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @functionexpr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @localtypeaccess +| 1 = @typedecl +| 2 = @keywordtypeexpr +| 3 = @stringliteraltypeexpr +| 4 = @numberliteraltypeexpr +| 5 = @booleanliteraltypeexpr +| 6 = @arraytypeexpr +| 7 = @uniontypeexpr +| 8 = @indexedaccesstypeexpr +| 9 = @intersectiontypeexpr +| 10 = @parenthesizedtypeexpr +| 11 = @tupletypeexpr +| 12 = @keyoftypeexpr +| 13 = @qualifiedtypeaccess +| 14 = @generictypeexpr +| 15 = @typelabel +| 16 = @typeoftypeexpr +| 17 = @localvartypeaccess +| 18 = @qualifiedvartypeaccess +| 19 = @thisvartypeaccess +| 20 = @predicatetypeexpr +| 21 = @interfacetypeexpr +| 22 = @typeparameter +| 23 = @plainfunctiontypeexpr +| 24 = @constructortypeexpr +| 25 = @localnamespaceaccess +| 26 = @qualifiednamespaceaccess +| 27 = @mappedtypeexpr +| 28 = @conditionaltypeexpr +| 29 = @infertypeexpr +| 30 = @importtypeaccess +| 31 = @importnamespaceaccess +| 32 = @importvartypeaccess +| 33 = @optionaltypeexpr +| 34 = @resttypeexpr +| 35 = @bigintliteraltypeexpr +| 36 = @readonlytypeexpr +; + +@typeref = @typeaccess | @typedecl; +@typeidentifier = @typedecl | @localtypeaccess | @typelabel | @localvartypeaccess | @localnamespaceaccess; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literaltypeexpr = @stringliteraltypeexpr | @numberliteraltypeexpr | @booleanliteraltypeexpr | @bigintliteraltypeexpr; +@typeaccess = @localtypeaccess | @qualifiedtypeaccess | @importtypeaccess; +@vartypeaccess = @localvartypeaccess | @qualifiedvartypeaccess | @thisvartypeaccess | @importvartypeaccess; +@namespaceaccess = @localnamespaceaccess | @qualifiednamespaceaccess | @importnamespaceaccess; +@importtypeexpr = @importtypeaccess | @importnamespaceaccess | @importvartypeaccess; + +@functiontypeexpr = @plainfunctiontypeexpr | @constructortypeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @anytype +| 1 = @stringtype +| 2 = @numbertype +| 3 = @uniontype +| 4 = @truetype +| 5 = @falsetype +| 6 = @typereference +| 7 = @objecttype +| 8 = @canonicaltypevariabletype +| 9 = @typeoftype +| 10 = @voidtype +| 11 = @undefinedtype +| 12 = @nulltype +| 13 = @nevertype +| 14 = @plainsymboltype +| 15 = @uniquesymboltype +| 16 = @objectkeywordtype +| 17 = @intersectiontype +| 18 = @tupletype +| 19 = @lexicaltypevariabletype +| 20 = @thistype +| 21 = @numberliteraltype +| 22 = @stringliteraltype +| 23 = @unknowntype +| 24 = @biginttype +| 25 = @bigintliteraltype +; + +@booleanliteraltype = @truetype | @falsetype; +@symboltype = @plainsymboltype | @uniquesymboltype; +@unionorintersectiontype = @uniontype | @intersectiontype; +@typevariabletype = @canonicaltypevariabletype | @lexicaltypevariabletype; + +hasAssertsKeyword(int node: @predicatetypeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @typereference | @typevariabletype | @typeoftype | @uniquesymboltype; +@ast_node_with_symbol = @typedefinition | @namespacedefinition | @toplevel | @typeaccess | @namespaceaccess | @vardecl | @function | @invokeexpr | @importdeclaration | @externalmodulereference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literaltype = @stringliteraltype | @numberliteraltype | @booleanliteraltype | @bigintliteraltype; +@type_with_literal_value = @stringliteraltype | @numberliteraltype | @bigintliteraltype; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @typereference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +#keyset[tuple, index] +tuple_element_name ( + int tuple: @tupletypeexpr ref, + int index: int ref, + varchar(900) name: string ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment +| 2 = @doccomment +| 3 = @htmlcommentstart +| 4 = @htmlcommentend; + +@htmlcomment = @htmlcommentstart | @htmlcommentend; +@linecomment = @slashslashcomment | @htmlcomment; +@blockcomment = @slashstarcomment | @doccomment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +jsParseErrors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexpliteral | @stringliteral; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexpParseErrors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +isGreedy (int id: @regexp_quantifier ref); +rangeQuantifierLowerBound (unique int id: @regexp_range ref, int lo: int ref); +rangeQuantifierUpperBound (unique int id: @regexp_range ref, int hi: int ref); +isCapture (unique int id: @regexp_group ref, int number: int ref); +isNamedCapture (unique int id: @regexp_group ref, string name: string ref); +isInverted (int id: @regexp_char_class ref); +regexpConstValue (unique int id: @regexp_constant ref, varchar(1) value: string ref); +charClassEscape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +namedBackref (unique int id: @regexp_backref ref, string name: string ref); +unicodePropertyEscapeName (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicodePropertyEscapeValue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @exprparent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* 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; + +@dataflownode = @expr | @functiondeclstmt | @classdeclstmt | @namespacedeclaration | @enumdeclaration | @property; + +@optionalchainable = @callexpr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/upgrade.properties b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/upgrade.properties new file mode 100644 index 00000000000..dc0d1654262 --- /dev/null +++ b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/upgrade.properties @@ -0,0 +1,2 @@ +description: add support for TypeScript 4.0 +compatibility: backwards From a7a016c5df3ee65c489464fd618fc03077e25f34 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 12 Aug 2020 13:29:43 +0200 Subject: [PATCH 025/146] update expected output --- .../ql/test/library-tests/TypeScript/Types/GetExprType.expected | 2 -- 1 file changed, 2 deletions(-) diff --git a/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected b/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected index 30eb614d5c3..f5b8bf8eaa9 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected @@ -67,12 +67,10 @@ | tst.ts:26:15:26:24 | () => void | () => void | | tst.ts:27:5:27:17 | undefinedType | undefined | | tst.ts:28:5:28:12 | nullType | null | -| tst.ts:28:22:28:25 | null | null | | tst.ts:29:5:29:13 | neverType | () => never | | tst.ts:29:16:29:26 | () => never | () => never | | tst.ts:30:5:30:14 | symbolType | symbol | | tst.ts:31:7:31:22 | uniqueSymbolType | typeof uniqueSymbolType | -| tst.ts:31:41:31:44 | null | null | | tst.ts:32:5:32:14 | objectType | object | | tst.ts:33:5:33:16 | intersection | string & { x: string; } | | tst.ts:33:29:33:29 | x | string | From fd9eb1d40b82e593aa43749101c9f34e92449ada Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 12 Aug 2020 16:55:55 +0200 Subject: [PATCH 026/146] use Identifier instead of just a plain string when getting tuple-element-names --- .../extractor/src/com/semmle/js/ast/NodeCopier.java | 2 +- .../src/com/semmle/js/extractor/ASTExtractor.java | 5 ++--- .../semmle/js/parser/TypeScriptASTConverter.java | 13 ++++--------- .../src/com/semmle/ts/ast/TupleTypeExpr.java | 7 ++++--- javascript/ql/src/semmle/javascript/TypeScript.qll | 11 ++++++++--- javascript/ql/src/semmlecode.javascript.dbscheme | 7 ------- .../TypeScript/TypeAnnotations/TupleTypeExpr.qll | 2 +- .../TypeScript/TypeAnnotations/tests.expected | 4 ++-- .../semmlecode.javascript.dbscheme | 7 ------- 9 files changed, 22 insertions(+), 36 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java b/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java index ddf57b32cff..00939503eeb 100644 --- a/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java +++ b/javascript/extractor/src/com/semmle/js/ast/NodeCopier.java @@ -705,7 +705,7 @@ public class NodeCopier implements Visitor { @Override public INode visit(TupleTypeExpr nd, Void c) { - return new TupleTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()), nd.getElementNames()); + return new TupleTypeExpr(visit(nd.getLoc()), copy(nd.getElementTypes()), copy(nd.getElementNames())); } @Override diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 4bf57075b0b..1050590f14d 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -1820,9 +1820,8 @@ public class ASTExtractor { public Label visit(TupleTypeExpr nd, Context c) { Label key = super.visit(nd, c); if (nd.getElementNames() != null) { - for (int i = 0; i < nd.getElementNames().size(); i++) { - trapwriter.addTuple("tuple_element_name", key, i, nd.getElementNames().get(i)); - } + // Element names are index -1, -2, -3... + visitAll(nd.getElementNames(), key, IdContext.typeDecl, -1, -1); } visitAll(nd.getElementTypes(), key, IdContext.typeBind, 0); return key; diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 83529f8b1b4..546739d7f28 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -2183,18 +2183,13 @@ public class TypeScriptASTConverter { List elements = new ArrayList<>(); ((JsonArray)node.get("elements")).iterator().forEachRemaining(elements::add); - List elementNames = elements.stream() + List names = convertNodes(elements.stream() .filter(n -> getKind(n).equals("NamedTupleMember")) .map(n -> n.getAsJsonObject().get("name")) - .map(n -> n.getAsJsonObject().get("escapedText")) - .map(n -> n.getAsString()) - .collect(Collectors.toList()); + .collect(Collectors.toList()) + ); - if (elementNames.size() == 0) { - elementNames = null; - } - - return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements"), elementNames); + return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements"), names); } // This method just does a trivial forward to the type. The names have already been extracted in `convertTupleType`. diff --git a/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java b/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java index 9d49899fafd..a42df41847e 100644 --- a/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java +++ b/javascript/extractor/src/com/semmle/ts/ast/TupleTypeExpr.java @@ -1,5 +1,6 @@ package com.semmle.ts.ast; +import com.semmle.js.ast.Identifier; import com.semmle.js.ast.SourceLocation; import com.semmle.js.ast.Visitor; import java.util.List; @@ -7,9 +8,9 @@ import java.util.List; /** A tuple type, such as [number, string]. */ public class TupleTypeExpr extends TypeExpression { private final List elementTypes; - private final List elementNames; + private final List elementNames; - public TupleTypeExpr(SourceLocation loc, List elementTypes, List elementNames) { + public TupleTypeExpr(SourceLocation loc, List elementTypes, List elementNames) { super("TupleTypeExpr", loc); this.elementTypes = elementTypes; this.elementNames = elementNames; @@ -19,7 +20,7 @@ public class TupleTypeExpr extends TypeExpression { return elementTypes; } - public List getElementNames() { + public List getElementNames() { return elementNames; } diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 82088638a60..799f386e2a0 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -846,7 +846,7 @@ class ParenthesizedTypeExpr extends @parenthesizedtypeexpr, TypeExpr { */ class TupleTypeExpr extends @tupletypeexpr, TypeExpr { /** Gets the `n`th element type in the tuple, starting at 0. */ - TypeExpr getElementType(int n) { result = getChildTypeExpr(n) } + TypeExpr getElementType(int n) { result = getChildTypeExpr(n) and n >= 0 } /** Gets any of the element types in the tuple. */ TypeExpr getAnElementType() { result = getElementType(_) } @@ -854,8 +854,13 @@ class TupleTypeExpr extends @tupletypeexpr, TypeExpr { /** Gets the number of elements in the tuple type. */ int getNumElementType() { result = count(getAnElementType()) } - /** Gets the name of the `n`th tuple member if the tuple members are named. */ - string getElementName(int n) { tuple_element_name(this, n, result) } + /** + * Gets the name of the `n`th tuple member, starting at 0. + * Only has a result if the tuple members are named. + * + * Type element names are at indices -1, -2, -3, ... + */ + Identifier getElementName(int n) { result = getChild(-(n + 1)) and n >= 0 } } /** diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index 3f291931cb8..c73fbfca57f 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -790,13 +790,6 @@ tuple_type_rest( unique int typ: @type ref ); -#keyset[tuple, index] -tuple_element_name ( - int tuple: @tupletypeexpr ref, - int index: int ref, - varchar(900) name: string ref -); - // comments comments (unique int id: @comment, int kind: int ref, diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll index 03fe4325786..adabff94060 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/TupleTypeExpr.qll @@ -4,6 +4,6 @@ query predicate test_TupleTypeExpr(TupleTypeExpr type, int n, int res0, TypeExpr res0 = type.getNumElementType() and res1 = type.getElementType(n) } -query predicate test_TupleTypeElementName(TupleTypeExpr type, int n, string name) { +query predicate test_TupleTypeElementName(TupleTypeExpr type, int n, Identifier name) { name = type.getElementName(n) } diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 00bda23ab3f..9ae9bdfe456 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -219,8 +219,8 @@ test_TupleTypeExpr | tst.ts:179:21:179:44 | [...Str ... umbers] | 0 | 2 | tst.ts:179:22:179:31 | ...Strings | | tst.ts:179:21:179:44 | [...Str ... umbers] | 1 | 2 | tst.ts:179:34:179:43 | ...Numbers | test_TupleTypeElementName -| tst.ts:169:34:169:64 | [first: ... number] | 0 | first | -| tst.ts:169:34:169:64 | [first: ... number] | 1 | second | +| tst.ts:169:34:169:64 | [first: ... number] | 0 | tst.ts:169:35:169:39 | first | +| tst.ts:169:34:169:64 | [first: ... number] | 1 | tst.ts:169:50:169:55 | second | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | diff --git a/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme index 3f291931cb8..c73fbfca57f 100644 --- a/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme +++ b/javascript/upgrades/2dc7a0389827d235763a3748aba73c2d4a677b15/semmlecode.javascript.dbscheme @@ -790,13 +790,6 @@ tuple_type_rest( unique int typ: @type ref ); -#keyset[tuple, index] -tuple_element_name ( - int tuple: @tupletypeexpr ref, - int index: int ref, - varchar(900) name: string ref -); - // comments comments (unique int id: @comment, int kind: int ref, From d95d427c5b6019792cf53902df771bcd0b9068dd Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 13 Aug 2020 09:22:32 +0200 Subject: [PATCH 027/146] better support for the `&&=`, `||=`, and `??=` operators --- .../com/semmle/js/extractor/CFGExtractor.java | 23 +- .../js/parser/TypeScriptASTConverter.java | 3 + .../ql/test/library-tests/Expr/assignment2.ts | 9 + .../ql/test/library-tests/Expr/tests.expected | 120 ++++ .../CWE-022/TaintedPath/TaintedPath.expected | 541 ++++++++++++++++++ .../CWE-022/TaintedPath/typescript.ts | 34 ++ 6 files changed, 728 insertions(+), 2 deletions(-) create mode 100644 javascript/ql/test/library-tests/Expr/assignment2.ts create mode 100644 javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/typescript.ts diff --git a/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java index 2aeba574bae..a43bd82f33b 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/CFGExtractor.java @@ -1551,8 +1551,27 @@ public class CFGExtractor { @Override public Void visit(AssignmentExpression nd, SuccessorInfo i) { - visitAssign(nd, nd.getLeft(), nd.getRight()); - succ(nd, i.getGuardedSuccessors(nd)); + // `a &&= b` expands to `a || (a = b);` + // The CFG is a conditional assignment, so we go through the assignment `nd` last. + if ("&&=".equals(nd.getOperator()) || "||=".equals(nd.getOperator()) || "??=".equals(nd.getOperator())) { + if ("&&=".equals(nd.getOperator())) { + // from lhs to rhs on truthy. from lhs to false-branch on falsy. + visit(nd.getLeft(), First.of(nd.getRight()), i.getSuccessors(false)); + } else if ("||=".equals(nd.getOperator())) { + // from lhs to true-branch on truthy. from lhs to rhs on falsy. + visit(nd.getLeft(), i.getSuccessors(true), First.of(nd.getRight())); + } else { // "??=" + // the union of the above - truthyness is unknown. + visit(nd.getLeft(), union(First.of(nd.getRight()), i.getAllSuccessors()), null); + } + + visit(nd.getRight(), First.of(nd), null); // from right to assignment. + + succ(nd, i.getGuardedSuccessors(nd)); + } else { + visitAssign(nd, nd.getLeft(), nd.getRight()); + succ(nd, i.getGuardedSuccessors(nd)); + } return null; } diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 546739d7f28..8d9079a0b69 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -852,6 +852,9 @@ public class TypeScriptASTConverter { case ">>=": case "<<=": case ">>>=": + case "??=": + case "&&=": + case "||=": return new AssignmentExpression(loc, operator, convertLValue(left), right); default: diff --git a/javascript/ql/test/library-tests/Expr/assignment2.ts b/javascript/ql/test/library-tests/Expr/assignment2.ts new file mode 100644 index 00000000000..3300fd2bf74 --- /dev/null +++ b/javascript/ql/test/library-tests/Expr/assignment2.ts @@ -0,0 +1,9 @@ +let a = 2; +let b = 3; + +a = 23; +a += 19; + +a &&= 4; +a ||= 5; +a ??= 6; \ No newline at end of file diff --git a/javascript/ql/test/library-tests/Expr/tests.expected b/javascript/ql/test/library-tests/Expr/tests.expected index 1c3963b50ea..fc0734b34c2 100644 --- a/javascript/ql/test/library-tests/Expr/tests.expected +++ b/javascript/ql/test/library-tests/Expr/tests.expected @@ -1,4 +1,25 @@ test_getParent +| assignment2.ts:1:5:1:5 | a | assignment2.ts:1:5:1:9 | a = 2 | +| assignment2.ts:1:5:1:9 | a = 2 | assignment2.ts:1:1:1:10 | let a = 2; | +| assignment2.ts:1:9:1:9 | 2 | assignment2.ts:1:5:1:9 | a = 2 | +| assignment2.ts:2:5:2:5 | b | assignment2.ts:2:5:2:9 | b = 3 | +| assignment2.ts:2:5:2:9 | b = 3 | assignment2.ts:2:1:2:10 | let b = 3; | +| assignment2.ts:2:9:2:9 | 3 | assignment2.ts:2:5:2:9 | b = 3 | +| assignment2.ts:4:1:4:1 | a | assignment2.ts:4:1:4:6 | a = 23 | +| assignment2.ts:4:1:4:6 | a = 23 | assignment2.ts:4:1:4:7 | a = 23; | +| assignment2.ts:4:5:4:6 | 23 | assignment2.ts:4:1:4:6 | a = 23 | +| assignment2.ts:5:1:5:1 | a | assignment2.ts:5:1:5:7 | a += 19 | +| assignment2.ts:5:1:5:7 | a += 19 | assignment2.ts:5:1:5:8 | a += 19; | +| assignment2.ts:5:6:5:7 | 19 | assignment2.ts:5:1:5:7 | a += 19 | +| assignment2.ts:7:1:7:1 | a | assignment2.ts:7:1:7:7 | a &&= 4 | +| assignment2.ts:7:1:7:7 | a &&= 4 | assignment2.ts:7:1:7:8 | a &&= 4; | +| assignment2.ts:7:7:7:7 | 4 | assignment2.ts:7:1:7:7 | a &&= 4 | +| assignment2.ts:8:1:8:1 | a | assignment2.ts:8:1:8:7 | a \|\|= 5 | +| assignment2.ts:8:1:8:7 | a \|\|= 5 | assignment2.ts:8:1:8:8 | a \|\|= 5; | +| assignment2.ts:8:7:8:7 | 5 | assignment2.ts:8:1:8:7 | a \|\|= 5 | +| assignment2.ts:9:1:9:1 | a | assignment2.ts:9:1:9:7 | a ??= 6 | +| assignment2.ts:9:1:9:7 | a ??= 6 | assignment2.ts:9:1:9:8 | a ??= 6; | +| assignment2.ts:9:7:9:7 | 6 | assignment2.ts:9:1:9:7 | a ??= 6 | | assignment.js:1:1:1:1 | a | assignment.js:1:1:1:6 | a = 23 | | assignment.js:1:1:1:6 | a = 23 | assignment.js:1:1:1:7 | a = 23; | | assignment.js:1:5:1:6 | 23 | assignment.js:1:1:1:6 | a = 23 | @@ -468,6 +489,27 @@ test_getParent | update.js:4:1:4:1 | b | update.js:4:1:4:3 | b-- | | update.js:4:1:4:3 | b-- | update.js:4:1:4:4 | b--; | test_getTopLevel +| assignment2.ts:1:5:1:5 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:1:5:1:9 | a = 2 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:1:9:1:9 | 2 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:2:5:2:5 | b | assignment2.ts:1:1:9:8 | | +| assignment2.ts:2:5:2:9 | b = 3 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:2:9:2:9 | 3 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:4:1:4:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:4:1:4:6 | a = 23 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:4:5:4:6 | 23 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:5:1:5:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:5:1:5:7 | a += 19 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:5:6:5:7 | 19 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:7:1:7:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:7:1:7:7 | a &&= 4 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:7:7:7:7 | 4 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:8:1:8:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:8:1:8:7 | a \|\|= 5 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:8:7:8:7 | 5 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:9:1:9:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:9:1:9:7 | a ??= 6 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:9:7:9:7 | 6 | assignment2.ts:1:1:9:8 | | | assignment.js:1:1:1:1 | a | assignment.js:1:1:12:7 | | | assignment.js:1:1:1:6 | a = 23 | assignment.js:1:1:12:7 | | | assignment.js:1:5:1:6 | 23 | assignment.js:1:1:12:7 | | @@ -937,6 +979,20 @@ test_getTopLevel | update.js:4:1:4:1 | b | update.js:1:1:5:0 | | | update.js:4:1:4:3 | b-- | update.js:1:1:5:0 | | test_getChild +| assignment2.ts:1:5:1:9 | a = 2 | 0 | assignment2.ts:1:5:1:5 | a | +| assignment2.ts:1:5:1:9 | a = 2 | 1 | assignment2.ts:1:9:1:9 | 2 | +| assignment2.ts:2:5:2:9 | b = 3 | 0 | assignment2.ts:2:5:2:5 | b | +| assignment2.ts:2:5:2:9 | b = 3 | 1 | assignment2.ts:2:9:2:9 | 3 | +| assignment2.ts:4:1:4:6 | a = 23 | 0 | assignment2.ts:4:1:4:1 | a | +| assignment2.ts:4:1:4:6 | a = 23 | 1 | assignment2.ts:4:5:4:6 | 23 | +| assignment2.ts:5:1:5:7 | a += 19 | 0 | assignment2.ts:5:1:5:1 | a | +| assignment2.ts:5:1:5:7 | a += 19 | 1 | assignment2.ts:5:6:5:7 | 19 | +| assignment2.ts:7:1:7:7 | a &&= 4 | 0 | assignment2.ts:7:1:7:1 | a | +| assignment2.ts:7:1:7:7 | a &&= 4 | 1 | assignment2.ts:7:7:7:7 | 4 | +| assignment2.ts:8:1:8:7 | a \|\|= 5 | 0 | assignment2.ts:8:1:8:1 | a | +| assignment2.ts:8:1:8:7 | a \|\|= 5 | 1 | assignment2.ts:8:7:8:7 | 5 | +| assignment2.ts:9:1:9:7 | a ??= 6 | 0 | assignment2.ts:9:1:9:1 | a | +| assignment2.ts:9:1:9:7 | a ??= 6 | 1 | assignment2.ts:9:7:9:7 | 6 | | assignment.js:1:1:1:6 | a = 23 | 0 | assignment.js:1:1:1:1 | a | | assignment.js:1:1:1:6 | a = 23 | 1 | assignment.js:1:5:1:6 | 23 | | assignment.js:2:1:2:7 | a += 19 | 0 | assignment.js:2:1:2:1 | a | @@ -1213,6 +1269,20 @@ test_getChild | update.js:3:1:3:3 | --b | 0 | update.js:3:3:3:3 | b | | update.js:4:1:4:3 | b-- | 0 | update.js:4:1:4:1 | b | test_isPure +| assignment2.ts:1:5:1:5 | a | +| assignment2.ts:1:9:1:9 | 2 | +| assignment2.ts:2:5:2:5 | b | +| assignment2.ts:2:9:2:9 | 3 | +| assignment2.ts:4:1:4:1 | a | +| assignment2.ts:4:5:4:6 | 23 | +| assignment2.ts:5:1:5:1 | a | +| assignment2.ts:5:6:5:7 | 19 | +| assignment2.ts:7:1:7:1 | a | +| assignment2.ts:7:7:7:7 | 4 | +| assignment2.ts:8:1:8:1 | a | +| assignment2.ts:8:7:8:7 | 5 | +| assignment2.ts:9:1:9:1 | a | +| assignment2.ts:9:7:9:7 | 6 | | assignment.js:1:1:1:1 | a | | assignment.js:1:5:1:6 | 23 | | assignment.js:2:1:2:1 | a | @@ -1708,6 +1778,27 @@ test_stripParens | primaries.js:28:2:28:5 | (42) | primaries.js:28:3:28:4 | 42 | | unary.js:6:5:6:7 | (0) | unary.js:6:6:6:6 | 0 | test_getContainer +| assignment2.ts:1:5:1:5 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:1:5:1:9 | a = 2 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:1:9:1:9 | 2 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:2:5:2:5 | b | assignment2.ts:1:1:9:8 | | +| assignment2.ts:2:5:2:9 | b = 3 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:2:9:2:9 | 3 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:4:1:4:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:4:1:4:6 | a = 23 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:4:5:4:6 | 23 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:5:1:5:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:5:1:5:7 | a += 19 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:5:6:5:7 | 19 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:7:1:7:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:7:1:7:7 | a &&= 4 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:7:7:7:7 | 4 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:8:1:8:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:8:1:8:7 | a \|\|= 5 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:8:7:8:7 | 5 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:9:1:9:1 | a | assignment2.ts:1:1:9:8 | | +| assignment2.ts:9:1:9:7 | a ??= 6 | assignment2.ts:1:1:9:8 | | +| assignment2.ts:9:7:9:7 | 6 | assignment2.ts:1:1:9:8 | | | assignment.js:1:1:1:1 | a | assignment.js:1:1:12:7 | | | assignment.js:1:1:1:6 | a = 23 | assignment.js:1:1:12:7 | | | assignment.js:1:5:1:6 | 23 | assignment.js:1:1:12:7 | | @@ -2177,6 +2268,27 @@ test_getContainer | update.js:4:1:4:1 | b | update.js:1:1:5:0 | | | update.js:4:1:4:3 | b-- | update.js:1:1:5:0 | | test_getEnclosingStmt +| assignment2.ts:1:5:1:5 | a | assignment2.ts:1:1:1:10 | let a = 2; | +| assignment2.ts:1:5:1:9 | a = 2 | assignment2.ts:1:1:1:10 | let a = 2; | +| assignment2.ts:1:9:1:9 | 2 | assignment2.ts:1:1:1:10 | let a = 2; | +| assignment2.ts:2:5:2:5 | b | assignment2.ts:2:1:2:10 | let b = 3; | +| assignment2.ts:2:5:2:9 | b = 3 | assignment2.ts:2:1:2:10 | let b = 3; | +| assignment2.ts:2:9:2:9 | 3 | assignment2.ts:2:1:2:10 | let b = 3; | +| assignment2.ts:4:1:4:1 | a | assignment2.ts:4:1:4:7 | a = 23; | +| assignment2.ts:4:1:4:6 | a = 23 | assignment2.ts:4:1:4:7 | a = 23; | +| assignment2.ts:4:5:4:6 | 23 | assignment2.ts:4:1:4:7 | a = 23; | +| assignment2.ts:5:1:5:1 | a | assignment2.ts:5:1:5:8 | a += 19; | +| assignment2.ts:5:1:5:7 | a += 19 | assignment2.ts:5:1:5:8 | a += 19; | +| assignment2.ts:5:6:5:7 | 19 | assignment2.ts:5:1:5:8 | a += 19; | +| assignment2.ts:7:1:7:1 | a | assignment2.ts:7:1:7:8 | a &&= 4; | +| assignment2.ts:7:1:7:7 | a &&= 4 | assignment2.ts:7:1:7:8 | a &&= 4; | +| assignment2.ts:7:7:7:7 | 4 | assignment2.ts:7:1:7:8 | a &&= 4; | +| assignment2.ts:8:1:8:1 | a | assignment2.ts:8:1:8:8 | a \|\|= 5; | +| assignment2.ts:8:1:8:7 | a \|\|= 5 | assignment2.ts:8:1:8:8 | a \|\|= 5; | +| assignment2.ts:8:7:8:7 | 5 | assignment2.ts:8:1:8:8 | a \|\|= 5; | +| assignment2.ts:9:1:9:1 | a | assignment2.ts:9:1:9:8 | a ??= 6; | +| assignment2.ts:9:1:9:7 | a ??= 6 | assignment2.ts:9:1:9:8 | a ??= 6; | +| assignment2.ts:9:7:9:7 | 6 | assignment2.ts:9:1:9:8 | a ??= 6; | | assignment.js:1:1:1:1 | a | assignment.js:1:1:1:7 | a = 23; | | assignment.js:1:1:1:6 | a = 23 | assignment.js:1:1:1:7 | a = 23; | | assignment.js:1:5:1:6 | 23 | assignment.js:1:1:1:7 | a = 23; | @@ -2612,6 +2724,14 @@ test_getEnclosingStmt | update.js:4:1:4:1 | b | update.js:4:1:4:4 | b--; | | update.js:4:1:4:3 | b-- | update.js:4:1:4:4 | b--; | test_inNullSensitiveContext +| assignment2.ts:5:1:5:1 | a | +| assignment2.ts:5:6:5:7 | 19 | +| assignment2.ts:7:1:7:1 | a | +| assignment2.ts:7:7:7:7 | 4 | +| assignment2.ts:8:1:8:1 | a | +| assignment2.ts:8:7:8:7 | 5 | +| assignment2.ts:9:1:9:1 | a | +| assignment2.ts:9:7:9:7 | 6 | | assignment.js:2:1:2:1 | a | | assignment.js:2:6:2:7 | 19 | | assignment.js:3:1:3:1 | a | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected index 7f6ca553576..7e4ab1a0427 100644 --- a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected @@ -3048,6 +3048,239 @@ nodes | torrents.js:7:25:7:27 | loc | | torrents.js:7:25:7:27 | loc | | torrents.js:7:25:7:27 | loc | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:24:9:30 | req.url | +| typescript.ts:9:24:9:30 | req.url | +| typescript.ts:9:24:9:30 | req.url | +| typescript.ts:9:24:9:30 | req.url | +| typescript.ts:9:24:9:30 | req.url | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:12:29:12:32 | path | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:20:15:20:18 | path | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:21:39:21:43 | path3 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:23:15:23:18 | path | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:24:39:24:43 | path4 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:30:15:30:18 | path | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | +| typescript.ts:32:29:32:33 | path6 | | views.js:1:43:1:55 | req.params[0] | | views.js:1:43:1:55 | req.params[0] | | views.js:1:43:1:55 | req.params[0] | @@ -7362,6 +7595,310 @@ edges | torrents.js:6:24:6:27 | name | torrents.js:6:12:6:45 | dir + " ... t.data" | | torrents.js:6:24:6:27 | name | torrents.js:6:12:6:45 | dir + " ... t.data" | | torrents.js:6:24:6:27 | name | torrents.js:6:12:6:45 | dir + " ... t.data" | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:12:29:12:32 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:20:15:20:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:23:15:23:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:7:9:48 | path | typescript.ts:30:15:30:18 | path | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:37 | url.par ... , true) | typescript.ts:9:14:9:43 | url.par ... ).query | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:43 | url.par ... ).query | typescript.ts:9:14:9:48 | url.par ... ry.path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:14:9:48 | url.par ... ry.path | typescript.ts:9:7:9:48 | path | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:9:24:9:30 | req.url | typescript.ts:9:14:9:37 | url.par ... , true) | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:7:20:18 | path3 | typescript.ts:21:39:21:43 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:20:15:20:18 | path | typescript.ts:20:7:20:18 | path3 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:7:23:18 | path4 | typescript.ts:24:39:24:43 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:23:15:23:18 | path | typescript.ts:23:7:23:18 | path4 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:7:30:18 | path6 | typescript.ts:32:29:32:33 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | +| typescript.ts:30:15:30:18 | path | typescript.ts:30:7:30:18 | path6 | | views.js:1:43:1:55 | req.params[0] | views.js:1:43:1:55 | req.params[0] | #select | TaintedPath-es6.js:10:26:10:45 | join("public", path) | TaintedPath-es6.js:7:20:7:26 | req.url | TaintedPath-es6.js:10:26:10:45 | join("public", path) | This path depends on $@. | TaintedPath-es6.js:7:20:7:26 | req.url | a user-provided value | @@ -7497,4 +8034,8 @@ edges | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:26:18:26:45 | path.sp ... hatever | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | tainted-string-steps.js:6:24:6:30 | req.url | tainted-string-steps.js:27:18:27:36 | path.split(unknown) | This path depends on $@. | tainted-string-steps.js:6:24:6:30 | req.url | a user-provided value | | torrents.js:7:25:7:27 | loc | torrents.js:5:13:5:38 | parseTo ... t).name | torrents.js:7:25:7:27 | loc | This path depends on $@. | torrents.js:5:13:5:38 | parseTo ... t).name | a user-provided value | +| typescript.ts:12:29:12:32 | path | typescript.ts:9:24:9:30 | req.url | typescript.ts:12:29:12:32 | path | This path depends on $@. | typescript.ts:9:24:9:30 | req.url | a user-provided value | +| typescript.ts:21:39:21:43 | path3 | typescript.ts:9:24:9:30 | req.url | typescript.ts:21:39:21:43 | path3 | This path depends on $@. | typescript.ts:9:24:9:30 | req.url | a user-provided value | +| typescript.ts:24:39:24:43 | path4 | typescript.ts:9:24:9:30 | req.url | typescript.ts:24:39:24:43 | path4 | This path depends on $@. | typescript.ts:9:24:9:30 | req.url | a user-provided value | +| typescript.ts:32:29:32:33 | path6 | typescript.ts:9:24:9:30 | req.url | typescript.ts:32:29:32:33 | path6 | This path depends on $@. | typescript.ts:9:24:9:30 | req.url | a user-provided value | | views.js:1:43:1:55 | req.params[0] | views.js:1:43:1:55 | req.params[0] | views.js:1:43:1:55 | req.params[0] | This path depends on $@. | views.js:1:43:1:55 | req.params[0] | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/typescript.ts b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/typescript.ts new file mode 100644 index 00000000000..f5fd62b2ee0 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/typescript.ts @@ -0,0 +1,34 @@ +var fs = require('fs'), + http = require('http'), + url = require('url'), + sanitize = require('sanitize-filename'), + pathModule = require('path') + ; + +var server = http.createServer(function(req, res) { + let path = url.parse(req.url, true).query.path; + + // BAD: This could read any file on the file system + res.write(fs.readFileSync(path)); + + if (path === 'foo.txt') + res.write(fs.readFileSync(path)); // GOOD: Path is compared to white-list + + let path2 = path; + path2 ||= res.write(fs.readFileSync(path2)); // GOOD: path is falsy + + let path3 = path; + path3 &&= res.write(fs.readFileSync(path3)); // BAD: path is truthy + + let path4 = path; + path4 ??= res.write(fs.readFileSync(path4)); // GOOD - path is null or undefined - but we don't capture that. [INCONSISTENCY] + + let path5 = path; + path5 &&= "clean"; + res.write(fs.readFileSync(path5)); // GOOD: path is either falsy or "clean"; + + let path6 = path; + path6 ||= "clean"; + res.write(fs.readFileSync(path6)); // BAD: path can still be tainted + +}); From d35d3f4271dabf653f4c3f9f910f5c274c77383c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 13 Aug 2020 09:37:55 +0200 Subject: [PATCH 028/146] add test for catch with type `unknown` --- .../library-tests/TypeScript/Types/GetExprType.expected | 7 +++++++ .../TypeScript/Types/GetTypeExprType.expected | 1 + .../library-tests/TypeScript/Types/UnknownType.expected | 2 ++ javascript/ql/test/library-tests/TypeScript/Types/tst.ts | 8 ++++++++ 4 files changed, 18 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected b/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected index f5b8bf8eaa9..f5e0d3d6748 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/GetExprType.expected @@ -90,6 +90,13 @@ | tst.ts:43:26:43:48 | { foo: ... s const | { readonly foo: "foo"; } | | tst.ts:43:28:43:30 | foo | "foo" | | tst.ts:43:33:43:37 | "foo" | "foo" | +| tst.ts:47:8:47:8 | e | unknown | +| tst.ts:48:7:48:14 | typeof e | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| tst.ts:48:7:48:27 | typeof ... string" | boolean | +| tst.ts:48:14:48:14 | e | unknown | +| tst.ts:48:20:48:27 | "string" | "string" | +| tst.ts:49:11:49:11 | b | string | +| tst.ts:49:24:49:24 | e | string | | type_alias.ts:3:5:3:5 | b | boolean | | type_alias.ts:7:5:7:5 | c | ValueOrArray | | type_alias.ts:14:9:14:32 | [proper ... ]: Json | any | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/GetTypeExprType.expected b/javascript/ql/test/library-tests/TypeScript/Types/GetTypeExprType.expected index 9254cf1febd..080d309f153 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/GetTypeExprType.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/GetTypeExprType.expected @@ -68,6 +68,7 @@ | tst.ts:39:60:39:65 | number | number | | tst.ts:39:60:39:67 | number[] | number[] | | tst.ts:40:18:40:24 | unknown | unknown | +| tst.ts:49:15:49:20 | string | string | | type_alias.ts:1:6:1:6 | B | boolean | | type_alias.ts:1:10:1:16 | boolean | boolean | | type_alias.ts:3:8:3:8 | B | boolean | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/UnknownType.expected b/javascript/ql/test/library-tests/TypeScript/Types/UnknownType.expected index dfc3f2808ed..abc98c3ecce 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/UnknownType.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/UnknownType.expected @@ -1 +1,3 @@ | tst.ts:40:5:40:15 | unknownType | unknown | +| tst.ts:47:8:47:8 | e | unknown | +| tst.ts:48:14:48:14 | e | unknown | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts index 7e426a30faa..04968386c99 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts @@ -41,3 +41,11 @@ let unknownType: unknown; let constArrayLiteral = [1, 2] as const; let constObjectLiteral = { foo: "foo" } as const; + + +try { } +catch (e: unknown) { + if (typeof e === "string") { + let b : string = e; + } +} \ No newline at end of file From 5ed31070452beabb70ff8d1dadbae32c02f8fd9a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 14 Aug 2020 11:12:23 +0200 Subject: [PATCH 029/146] Python: Start scaffold for magic methods --- python/ql/src/semmle/python/Magic.qll | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 python/ql/src/semmle/python/Magic.qll diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll new file mode 100644 index 00000000000..bbea1f90d1d --- /dev/null +++ b/python/ql/src/semmle/python/Magic.qll @@ -0,0 +1,36 @@ +import python + +module MagicMethod { + abstract class Potential extends ControlFlowNode { + abstract string getMagicMethodName(); + abstract ControlFlowNode getArg(int n); + ControlFlowNode getSelf() { result = this.getArg(1) } + } + + class Actual extends ControlFlowNode { + Object resolvedMagicMethod; + + Actual() { + exists(Potential pot | + this.(Potential) = pot and + pot.getSelf().(ClassObject).lookupAttribute(pot.getMagicMethodName()) = resolvedMagicMethod + ) + } + } +} + +class MagicBinOp extends MagicMethod::Potential, BinaryExprNode { + Operator operator; + + MagicBinOp() { this.getOp() = operator} + + override string getMagicMethodName() { + result = operator.getSpecialMethodName() + } + + override ControlFlowNode getArg(int n) { + n = 1 and result = this.getLeft() + or + n = 2 and result = this.getRight() + } +} From 360ddc6314439036a312d33615fa515a6717611f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 14 Aug 2020 13:25:17 +0200 Subject: [PATCH 030/146] Python: better charPred --- python/ql/src/semmle/python/Magic.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll index bbea1f90d1d..d277599b58d 100644 --- a/python/ql/src/semmle/python/Magic.qll +++ b/python/ql/src/semmle/python/Magic.qll @@ -8,14 +8,16 @@ module MagicMethod { } class Actual extends ControlFlowNode { - Object resolvedMagicMethod; + Value resolvedMagicMethod; Actual() { exists(Potential pot | this.(Potential) = pot and - pot.getSelf().(ClassObject).lookupAttribute(pot.getMagicMethodName()) = resolvedMagicMethod + pot.getSelf().pointsTo().getClass().lookup(pot.getMagicMethodName()) = resolvedMagicMethod ) } + + Value getResolvedMagicMethod() { result = resolvedMagicMethod } } } From e808d3033acfa0de5d4827c7e5eac53010f42d2f Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 14 Aug 2020 14:19:18 +0200 Subject: [PATCH 031/146] Python: Add magic to DataFlowCall --- .../dataflow/internal/DataFlowPrivate.qll | 65 +++++++++++++++++-- python/ql/src/semmle/python/Magic.qll | 6 +- .../coverage/classesCallGraph.expected | 26 ++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 1f46fd341e9..319bf69a414 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -1,5 +1,6 @@ private import python private import DataFlowPublic +import semmle.python.Magic //-------- // Data flow graph @@ -157,17 +158,67 @@ class DataFlowClassValue extends DataFlowCallable, TClassValue { override string getName() { result = c.getName() } } -/** Represents a call to a callable */ -class DataFlowCall extends CallNode { - DataFlowCallable callable; +newtype TDataFlowCall = + TCallNode(CallNode call) or + TMagicCall(MagicMethod::Actual magic) - DataFlowCall() { this = callable.getACall() } +abstract class DataFlowCall extends TDataFlowCall { + /** Gets a textual representation of this element. */ + abstract string toString(); /** Get the callable to which this call goes. */ - DataFlowCallable getCallable() { result = callable } + abstract DataFlowCallable getCallable(); + + /** Get the specified arguemnt to this call. */ + abstract ControlFlowNode getArg(int n); + + /** Get the control flow node representing this call. */ + abstract ControlFlowNode getNode(); /** Gets the enclosing callable of this call. */ - DataFlowCallable getEnclosingCallable() { result.getScope() = this.getNode().getScope() } + abstract DataFlowCallable getEnclosingCallable(); +} + + +/** Represents a call to a callable */ +class CallNodeCall extends DataFlowCall, TCallNode { + CallNode call; + DataFlowCallable callable; + + CallNodeCall() { + this = TCallNode(call) and + call = callable.getACall() + } + + override string toString() { result = call.toString() } + + override ControlFlowNode getArg(int n) { + result = call.getArg(n) + } + + override ControlFlowNode getNode() { result = call } + + override DataFlowCallable getCallable() { result = callable } + + override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() } +} + +class MagicCall extends DataFlowCall, TMagicCall { + MagicMethod::Actual magic; + + MagicCall() { this = TMagicCall(magic) } + + override string toString() { result = magic.toString() } + + override ControlFlowNode getArg(int n) { + result = magic.(MagicMethod::Potential).getArg(n) + } + + override ControlFlowNode getNode() { result = magic } + + override DataFlowCallable getCallable() { result = TCallableValue(magic.getResolvedMagicMethod()) } + + override DataFlowCallable getEnclosingCallable() { result.getScope() = magic.getNode().getScope() } } /** A data flow node that represents a call argument. */ @@ -220,7 +271,7 @@ class OutNode extends CfgNode { * `kind`. */ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) { - call = result.getNode() and + call.getNode() = result.getNode() and kind = TNormalReturnKind() } diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll index d277599b58d..e60b16c16ab 100644 --- a/python/ql/src/semmle/python/Magic.qll +++ b/python/ql/src/semmle/python/Magic.qll @@ -4,7 +4,7 @@ module MagicMethod { abstract class Potential extends ControlFlowNode { abstract string getMagicMethodName(); abstract ControlFlowNode getArg(int n); - ControlFlowNode getSelf() { result = this.getArg(1) } + ControlFlowNode getSelf() { result = this.getArg(0) } } class Actual extends ControlFlowNode { @@ -31,8 +31,8 @@ class MagicBinOp extends MagicMethod::Potential, BinaryExprNode { } override ControlFlowNode getArg(int n) { - n = 1 and result = this.getLeft() + n = 0 and result = this.getLeft() or - n = 2 and result = this.getRight() + n = 1 and result = this.getRight() } } diff --git a/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected b/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected index 4baf0b077ab..3a15759e3bd 100644 --- a/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected +++ b/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected @@ -4,3 +4,29 @@ | classes.py:182:7:182:26 | ControlFlowNode for dict() | classes.py:182:7:182:26 | ControlFlowNode for dict() | | classes.py:303:28:303:51 | ControlFlowNode for dict() | classes.py:303:28:303:51 | ControlFlowNode for dict() | | classes.py:466:12:466:24 | ControlFlowNode for Attribute() | classes.py:466:12:466:24 | ControlFlowNode for Attribute() | +| classes.py:505:3:505:10 | ControlFlowNode for with_add | classes.py:499:15:499:18 | SSA variable self | +| classes.py:505:14:505:21 | ControlFlowNode for with_add | classes.py:499:21:499:25 | SSA variable other | +| classes.py:516:3:516:10 | ControlFlowNode for with_sub | classes.py:510:15:510:18 | SSA variable self | +| classes.py:516:14:516:21 | ControlFlowNode for with_sub | classes.py:510:21:510:25 | SSA variable other | +| classes.py:527:3:527:10 | ControlFlowNode for with_mul | classes.py:521:15:521:18 | SSA variable self | +| classes.py:527:14:527:21 | ControlFlowNode for with_mul | classes.py:521:21:521:25 | SSA variable other | +| classes.py:538:3:538:13 | ControlFlowNode for with_matmul | classes.py:532:18:532:21 | SSA variable self | +| classes.py:538:17:538:27 | ControlFlowNode for with_matmul | classes.py:532:24:532:28 | SSA variable other | +| classes.py:549:3:549:14 | ControlFlowNode for with_truediv | classes.py:543:19:543:22 | SSA variable self | +| classes.py:549:18:549:29 | ControlFlowNode for with_truediv | classes.py:543:25:543:29 | SSA variable other | +| classes.py:560:3:560:15 | ControlFlowNode for with_floordiv | classes.py:554:20:554:23 | SSA variable self | +| classes.py:560:20:560:32 | ControlFlowNode for with_floordiv | classes.py:554:26:554:30 | SSA variable other | +| classes.py:571:3:571:10 | ControlFlowNode for with_mod | classes.py:565:15:565:18 | SSA variable self | +| classes.py:571:14:571:21 | ControlFlowNode for with_mod | classes.py:565:21:565:25 | SSA variable other | +| classes.py:597:3:597:10 | ControlFlowNode for with_pow | classes.py:587:15:587:18 | SSA variable self | +| classes.py:597:15:597:22 | ControlFlowNode for with_pow | classes.py:587:21:587:25 | SSA variable other | +| classes.py:608:3:608:13 | ControlFlowNode for with_lshift | classes.py:602:18:602:21 | SSA variable self | +| classes.py:608:18:608:28 | ControlFlowNode for with_lshift | classes.py:602:24:602:28 | SSA variable other | +| classes.py:619:3:619:13 | ControlFlowNode for with_rshift | classes.py:613:18:613:21 | SSA variable self | +| classes.py:619:18:619:28 | ControlFlowNode for with_rshift | classes.py:613:24:613:28 | SSA variable other | +| classes.py:630:3:630:10 | ControlFlowNode for with_and | classes.py:624:15:624:18 | SSA variable self | +| classes.py:630:14:630:21 | ControlFlowNode for with_and | classes.py:624:21:624:25 | SSA variable other | +| classes.py:641:3:641:10 | ControlFlowNode for with_xor | classes.py:635:15:635:18 | SSA variable self | +| classes.py:641:14:641:21 | ControlFlowNode for with_xor | classes.py:635:21:635:25 | SSA variable other | +| classes.py:652:3:652:9 | ControlFlowNode for with_or | classes.py:646:14:646:17 | SSA variable self | +| classes.py:652:13:652:19 | ControlFlowNode for with_or | classes.py:646:20:646:24 | SSA variable other | From 4bc04486cbcc637c38d420375beb25c4add97795 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 14 Aug 2020 14:41:35 +0200 Subject: [PATCH 032/146] Python: Annotate tests (as before the new feature) --- .../experimental/dataflow/coverage/classes.py | 200 +++++++++--------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index de06d284361..255bacf092a 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -8,14 +8,14 @@ # All functions starting with "test_" should run and print `"OK"`. # This can be checked by running validTest.py. -def OK(): +def OK() # Call not found: print("OK") # object.__new__(cls[, ...]) class With_new: def __new__(cls): - OK() + OK() # Call not found return super().__new__(cls) def test_new(): @@ -25,7 +25,7 @@ def test_new(): class With_init: def __init__(self): - OK() + OK() # Call not found def test_init(): with_init = With_init() @@ -34,7 +34,7 @@ def test_init(): class With_del: def __del__(self): - OK() + OK() # Call not found def test_del(): with_del = With_del() @@ -44,7 +44,7 @@ def test_del(): class With_repr: def __repr__(self): - OK() + OK() # Call not found return "With_repr()" def test_repr(): @@ -55,7 +55,7 @@ def test_repr(): class With_str: def __str__(self): - OK() + OK() # Call not found return "Awesome" def test_str(): @@ -66,7 +66,7 @@ def test_str(): class With_bytes: def __bytes__(self): - OK() + OK() # Call not found return b"Awesome" def test_bytes(): @@ -77,7 +77,7 @@ def test_bytes(): class With_format: def __format__(self, format_spec): - OK() + OK() # Call not found return "Awesome" def test_format(): @@ -96,7 +96,7 @@ def test_format_fstr(): class With_lt: def __lt__(self, other): - OK() + OK() # Call not found return "" def test_lt(): @@ -107,7 +107,7 @@ def test_lt(): class With_le: def __le__(self, other): - OK() + OK() # Call not found return "" def test_le(): @@ -118,7 +118,7 @@ def test_le(): class With_eq: def __eq__(self, other): - OK() + OK() # Call not found return "" def test_eq(): @@ -129,7 +129,7 @@ def test_eq(): class With_ne: def __ne__(self, other): - OK() + OK() # Call not found return "" def test_ne(): @@ -140,7 +140,7 @@ def test_ne(): class With_gt: def __gt__(self, other): - OK() + OK() # Call not found return "" def test_gt(): @@ -151,7 +151,7 @@ def test_gt(): class With_ge: def __ge__(self, other): - OK() + OK() # Call not found return "" def test_ge(): @@ -162,7 +162,7 @@ def test_ge(): class With_hash: def __hash__(self): - OK() + OK() # Call not found return 0 def test_hash(): @@ -185,7 +185,7 @@ def test_hash_dict(): class With_bool: def __bool__(self): - OK() + OK() # Call not found return True def test_bool(): @@ -202,7 +202,7 @@ def test_bool_if(): class With_getattr: def __getattr__(self, name): - OK() + OK() # Call not found return "" def test_getattr(): @@ -213,7 +213,7 @@ def test_getattr(): class With_getattribute: def __getattribute__(self, name): - OK() + OK() # Call not found return "" def test_getattribute(): @@ -224,7 +224,7 @@ def test_getattribute(): class With_setattr: def __setattr__(self, name, value): - OK() + OK() # Call not found def test_setattr(): with_setattr = With_setattr() @@ -234,7 +234,7 @@ def test_setattr(): class With_delattr: def __delattr__(self, name): - OK() + OK() # Call not found def test_delattr(): with_delattr = With_delattr() @@ -244,7 +244,7 @@ def test_delattr(): class With_dir: def __dir__(self): - OK() + OK() # Call not found return [] def test_dir(): @@ -260,7 +260,7 @@ class Owner: class With_get: def __get__(self, instance, owner=None): - OK() + OK() # Call not found return "" def test_get(): @@ -272,7 +272,7 @@ def test_get(): class With_set: def __set__(self, instance, value): - OK() + OK() # Call not found def test_set(): with_set = With_set() @@ -284,7 +284,7 @@ def test_set(): class With_delete: def __delete__(self, instance): - OK() + OK() # Call not found def test_delete(): with_delete = With_delete() @@ -296,7 +296,7 @@ def test_delete(): class With_set_name: def __set_name__(self, owner, name): - OK() + OK() # Call not found def test_set_name(): with_set_name = With_set_name() @@ -312,7 +312,7 @@ def test_set_name(): class With_init_subclass: def __init_subclass__(cls): - OK() + OK() # Call not found def test_init_subclass(): type("Subclass", (With_init_subclass,), {}) @@ -328,7 +328,7 @@ def test_init_subclass(): class With_prepare(type): def __prepare__(name, bases, **kwds): - OK() + OK() # Call not found return kwds @@ -341,7 +341,7 @@ def test_prepare(): class With_instancecheck: def __instancecheck__(self, instance): - OK() + OK() # Call not found return True def test_instancecheck(): @@ -352,7 +352,7 @@ def test_instancecheck(): class With_subclasscheck: def __subclasscheck__(self, subclass): - OK() + OK() # Call not found return True def test_subclasscheck(): @@ -365,7 +365,7 @@ def test_subclasscheck(): class With_class_getitem: def __class_getitem__(cls, key): - OK() + OK() # Call not found return object def test_class_getitem(): @@ -377,7 +377,7 @@ def test_class_getitem(): class With_call: def __call__(self): - OK() + OK() # Call not found def test_call(): with_call = With_call() @@ -388,7 +388,7 @@ def test_call(): class With_len: def __len__(self): - OK() + OK() # Call not found return 0 def test_len(): @@ -408,7 +408,7 @@ def test_len_if(): class With_length_hint: def __length_hint__(self): - OK() + OK() # Call not found return 0 def test_length_hint(): @@ -420,7 +420,7 @@ def test_length_hint(): class With_getitem: def __getitem__(self, key): - OK() + OK() # Call not found return "" def test_getitem(): @@ -431,7 +431,7 @@ def test_getitem(): class With_setitem: def __setitem__(self, key, value): - OK() + OK() # Call not found def test_setitem(): with_setitem = With_setitem() @@ -441,7 +441,7 @@ def test_setitem(): class With_delitem: def __delitem__(self, key): - OK() + OK() # Call not found def test_delitem(): with_delitem = With_delitem() @@ -451,7 +451,7 @@ def test_delitem(): class With_missing(dict): def __missing__(self, key): - OK() + OK() # Call not found return "" def test_missing(): @@ -462,7 +462,7 @@ def test_missing(): class With_iter: def __iter__(self): - OK() + OK() # Call not found return [].__iter__() def test_iter(): @@ -473,7 +473,7 @@ def test_iter(): class With_reversed: def __reversed__(self): - OK() + OK() # Call not found return [].__iter__ def test_reversed(): @@ -484,7 +484,7 @@ def test_reversed(): class With_contains: def __contains__(self, item): - OK() + OK() # Call not found return True def test_contains(): @@ -497,7 +497,7 @@ def test_contains(): class With_add: def __add__(self, other): - OK() + OK() # Call not found return self def test_add(): @@ -508,7 +508,7 @@ def test_add(): class With_sub: def __sub__(self, other): - OK() + OK() # Call not found return self def test_sub(): @@ -519,7 +519,7 @@ def test_sub(): class With_mul: def __mul__(self, other): - OK() + OK() # Call not found return self def test_mul(): @@ -530,7 +530,7 @@ def test_mul(): class With_matmul: def __matmul__(self, other): - OK() + OK() # Call not found return self def test_matmul(): @@ -541,7 +541,7 @@ def test_matmul(): class With_truediv: def __truediv__(self, other): - OK() + OK() # Call not found return self def test_truediv(): @@ -552,7 +552,7 @@ def test_truediv(): class With_floordiv: def __floordiv__(self, other): - OK() + OK() # Call not found return self def test_floordiv(): @@ -563,7 +563,7 @@ def test_floordiv(): class With_mod: def __mod__(self, other): - OK() + OK() # Call not found return self def test_mod(): @@ -574,7 +574,7 @@ def test_mod(): class With_divmod: def __divmod__(self, other): - OK() + OK() # Call not found return self def test_divmod(): @@ -585,7 +585,7 @@ def test_divmod(): class With_pow: def __pow__(self, other): - OK() + OK() # Call not found return self def test_pow(): @@ -600,7 +600,7 @@ def test_pow_op(): class With_lshift: def __lshift__(self, other): - OK() + OK() # Call not found return self def test_lshift(): @@ -611,7 +611,7 @@ def test_lshift(): class With_rshift: def __rshift__(self, other): - OK() + OK() # Call not found return self def test_rshift(): @@ -622,7 +622,7 @@ def test_rshift(): class With_and: def __and__(self, other): - OK() + OK() # Call not found return self def test_and(): @@ -633,7 +633,7 @@ def test_and(): class With_xor: def __xor__(self, other): - OK() + OK() # Call not found return self def test_xor(): @@ -644,7 +644,7 @@ def test_xor(): class With_or: def __or__(self, other): - OK() + OK() # Call not found return self def test_or(): @@ -655,7 +655,7 @@ def test_or(): class With_radd: def __radd__(self, other): - OK() + OK() # Call not found return self def test_radd(): @@ -666,7 +666,7 @@ def test_radd(): class With_rsub: def __rsub__(self, other): - OK() + OK() # Call not found return self def test_rsub(): @@ -677,7 +677,7 @@ def test_rsub(): class With_rmul: def __rmul__(self, other): - OK() + OK() # Call not found return self def test_rmul(): @@ -688,7 +688,7 @@ def test_rmul(): class With_rmatmul: def __rmatmul__(self, other): - OK() + OK() # Call not found return self def test_rmatmul(): @@ -699,7 +699,7 @@ def test_rmatmul(): class With_rtruediv: def __rtruediv__(self, other): - OK() + OK() # Call not found return self def test_rtruediv(): @@ -710,7 +710,7 @@ def test_rtruediv(): class With_rfloordiv: def __rfloordiv__(self, other): - OK() + OK() # Call not found return self def test_rfloordiv(): @@ -721,7 +721,7 @@ def test_rfloordiv(): class With_rmod: def __rmod__(self, other): - OK() + OK() # Call not found return self def test_rmod(): @@ -732,7 +732,7 @@ def test_rmod(): class With_rdivmod: def __rdivmod__(self, other): - OK() + OK() # Call not found return self def test_rdivmod(): @@ -743,7 +743,7 @@ def test_rdivmod(): class With_rpow: def __rpow__(self, other): - OK() + OK() # Call not found return self def test_rpow(): @@ -758,7 +758,7 @@ def test_rpow_op(): class With_rlshift: def __rlshift__(self, other): - OK() + OK() # Call not found return self def test_rlshift(): @@ -769,7 +769,7 @@ def test_rlshift(): class With_rrshift: def __rrshift__(self, other): - OK() + OK() # Call not found return self def test_rrshift(): @@ -780,7 +780,7 @@ def test_rrshift(): class With_rand: def __rand__(self, other): - OK() + OK() # Call not found return self def test_rand(): @@ -791,7 +791,7 @@ def test_rand(): class With_rxor: def __rxor__(self, other): - OK() + OK() # Call not found return self def test_rxor(): @@ -802,7 +802,7 @@ def test_rxor(): class With_ror: def __ror__(self, other): - OK() + OK() # Call not found return self def test_ror(): @@ -813,7 +813,7 @@ def test_ror(): class With_iadd: def __iadd__(self, other): - OK() + OK() # Call not found return self def test_iadd(): @@ -824,7 +824,7 @@ def test_iadd(): class With_isub: def __isub__(self, other): - OK() + OK() # Call not found return self def test_isub(): @@ -835,7 +835,7 @@ def test_isub(): class With_imul: def __imul__(self, other): - OK() + OK() # Call not found return self def test_imul(): @@ -846,7 +846,7 @@ def test_imul(): class With_imatmul: def __imatmul__(self, other): - OK() + OK() # Call not found return self def test_imatmul(): @@ -857,7 +857,7 @@ def test_imatmul(): class With_itruediv: def __itruediv__(self, other): - OK() + OK() # Call not found return self def test_itruediv(): @@ -868,7 +868,7 @@ def test_itruediv(): class With_ifloordiv: def __ifloordiv__(self, other): - OK() + OK() # Call not found return self def test_ifloordiv(): @@ -879,7 +879,7 @@ def test_ifloordiv(): class With_imod: def __imod__(self, other): - OK() + OK() # Call not found return self def test_imod(): @@ -890,7 +890,7 @@ def test_imod(): class With_ipow: def __ipow__(self, other): - OK() + OK() # Call not found return self def test_ipow(): @@ -901,7 +901,7 @@ def test_ipow(): class With_ilshift: def __ilshift__(self, other): - OK() + OK() # Call not found return self def test_ilshift(): @@ -912,7 +912,7 @@ def test_ilshift(): class With_irshift: def __irshift__(self, other): - OK() + OK() # Call not found return self def test_irshift(): @@ -923,7 +923,7 @@ def test_irshift(): class With_iand: def __iand__(self, other): - OK() + OK() # Call not found return self def test_iand(): @@ -934,7 +934,7 @@ def test_iand(): class With_ixor: def __ixor__(self, other): - OK() + OK() # Call not found return self def test_ixor(): @@ -945,7 +945,7 @@ def test_ixor(): class With_ior: def __ior__(self, other): - OK() + OK() # Call not found return self def test_ior(): @@ -956,7 +956,7 @@ def test_ior(): class With_neg: def __neg__(self): - OK() + OK() # Call not found return self def test_neg(): @@ -967,7 +967,7 @@ def test_neg(): class With_pos: def __pos__(self): - OK() + OK() # Call not found return self def test_pos(): @@ -978,7 +978,7 @@ def test_pos(): class With_abs: def __abs__(self): - OK() + OK() # Call not found return self def test_abs(): @@ -989,7 +989,7 @@ def test_abs(): class With_invert: def __invert__(self): - OK() + OK() # Call not found return self def test_invert(): @@ -1000,7 +1000,7 @@ def test_invert(): class With_complex: def __complex__(self): - OK() + OK() # Call not found return 0j def test_complex(): @@ -1011,7 +1011,7 @@ def test_complex(): class With_int: def __int__(self): - OK() + OK() # Call not found return 0 def test_int(): @@ -1022,7 +1022,7 @@ def test_int(): class With_float: def __float__(self): - OK() + OK() # Call not found return 0.0 def test_float(): @@ -1033,7 +1033,7 @@ def test_float(): class With_index: def __index__(self): - OK() + OK() # Call not found return 0 def test_index(): @@ -1073,7 +1073,7 @@ def test_index_complex(): class With_round: def __round__(self): - OK() + OK() # Call not found return 0 def test_round(): @@ -1084,7 +1084,7 @@ def test_round(): class With_trunc: def __trunc__(self): - OK() + OK() # Call not found return 0 def test_trunc(): @@ -1096,7 +1096,7 @@ def test_trunc(): class With_floor: def __floor__(self): - OK() + OK() # Call not found return 0 def test_floor(): @@ -1108,7 +1108,7 @@ def test_floor(): class With_ceil: def __ceil__(self): - OK() + OK() # Call not found return 0 def test_ceil(): @@ -1122,7 +1122,7 @@ def test_ceil(): class With_enter: def __enter__(self): - OK() + OK() # Call not found return def __exit__(self, exc_type, exc_value, traceback): @@ -1139,7 +1139,7 @@ class With_exit: return def __exit__(self, exc_type, exc_value, traceback): - OK() + OK() # Call not found return def test_exit(): @@ -1153,7 +1153,7 @@ import asyncio class With_await: def __await__(self): - OK() + OK() # Call not found return (yield from asyncio.coroutine(lambda: "")()) async def atest_await(): @@ -1171,7 +1171,7 @@ async def atest_await(): class With_aiter: def __aiter__(self): - OK() + OK() # Call not found return self async def __anext__(self): @@ -1189,7 +1189,7 @@ class With_anext: return self async def __anext__(self): - OK() + OK() # Call not found raise StopAsyncIteration async def atest_anext(): @@ -1203,7 +1203,7 @@ async def atest_anext(): class With_aenter: async def __aenter__(self): - OK() + OK() # Call not found async def __aexit__(self, exc_type, exc_value, traceback): pass @@ -1220,7 +1220,7 @@ class With_aexit: pass async def __aexit__(self, exc_type, exc_value, traceback): - OK() + OK() # Call not found async def atest_aexit(): with_aexit = With_aexit() From 7ea3fc04c82e405e977e96f0dd979218ce527f31 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 14 Aug 2020 14:46:39 +0200 Subject: [PATCH 033/146] Python: adjust test annotation (for after feature) --- .../experimental/dataflow/coverage/classes.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 255bacf092a..75abe0c82e2 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -497,7 +497,7 @@ def test_contains(): class With_add: def __add__(self, other): - OK() # Call not found + OK() return self def test_add(): @@ -508,7 +508,7 @@ def test_add(): class With_sub: def __sub__(self, other): - OK() # Call not found + OK() return self def test_sub(): @@ -519,7 +519,7 @@ def test_sub(): class With_mul: def __mul__(self, other): - OK() # Call not found + OK() return self def test_mul(): @@ -530,7 +530,7 @@ def test_mul(): class With_matmul: def __matmul__(self, other): - OK() # Call not found + OK() return self def test_matmul(): @@ -541,7 +541,7 @@ def test_matmul(): class With_truediv: def __truediv__(self, other): - OK() # Call not found + OK() return self def test_truediv(): @@ -552,7 +552,7 @@ def test_truediv(): class With_floordiv: def __floordiv__(self, other): - OK() # Call not found + OK() return self def test_floordiv(): @@ -563,7 +563,7 @@ def test_floordiv(): class With_mod: def __mod__(self, other): - OK() # Call not found + OK() return self def test_mod(): @@ -585,12 +585,12 @@ def test_divmod(): class With_pow: def __pow__(self, other): - OK() # Call not found + OK() return self def test_pow(): with_pow = With_pow() - pow(with_pow, with_pow) + pow(with_pow, with_pow) # Call not found def test_pow_op(): with_pow = With_pow() @@ -600,7 +600,7 @@ def test_pow_op(): class With_lshift: def __lshift__(self, other): - OK() # Call not found + OK() return self def test_lshift(): @@ -611,7 +611,7 @@ def test_lshift(): class With_rshift: def __rshift__(self, other): - OK() # Call not found + OK() return self def test_rshift(): @@ -622,7 +622,7 @@ def test_rshift(): class With_and: def __and__(self, other): - OK() # Call not found + OK() return self def test_and(): @@ -633,7 +633,7 @@ def test_and(): class With_xor: def __xor__(self, other): - OK() # Call not found + OK() return self def test_xor(): @@ -644,7 +644,7 @@ def test_xor(): class With_or: def __or__(self, other): - OK() # Call not found + OK() return self def test_or(): From 67fccac8a97f7902504eb079fa22a2a1c90cf8e6 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:13:03 +0200 Subject: [PATCH 034/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 82deffa60ca..01ff6ad34b2 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -16,7 +16,7 @@ module InsecureCookie { */ abstract class InsecureCookies extends DataFlow::Node { /** - * The name of the middleware/library used to set the cookie. + * Gets the name of the middleware/library used to set the cookie. */ abstract string getKind(); From 0c121062b6b2e6ceafff652403b8dbb0b58fd071 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:13:54 +0200 Subject: [PATCH 035/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 01ff6ad34b2..ad56e75186c 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -21,7 +21,7 @@ module InsecureCookie { abstract string getKind(); /** - * The `cookie` options. + * Gets the options used to set this cookie, if any. */ abstract DataFlow::Node getCookieOptionsArgument(); From 8d26b810eee5f8e2340998ea5a35fca33fb8d382 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:17:16 +0200 Subject: [PATCH 036/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index ad56e75186c..5f47f636dc7 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -33,7 +33,6 @@ module InsecureCookie { /** * A cookie set using the `express` module `cookie-session` (https://github.com/expressjs/cookie-session). - * The flag `secure` is set to `false` by default for HTTP, `true` by default for HTTPS (https://github.com/expressjs/cookie-session#cookie-options). */ class InsecureCookieSession extends ExpressLibraries::CookieSession::MiddlewareInstance, InsecureCookies { From 10bd745740e76ddb09fec19429f2e900d9680dda Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:18:54 +0200 Subject: [PATCH 037/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 5f47f636dc7..85d36daa6bd 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -41,7 +41,7 @@ module InsecureCookie { override string getKind() { result = "cookie-session" } override DataFlow::SourceNode getCookieOptionsArgument() { - result = this.getOption("cookie").(DataFlow::SourceNode) + result = this.getOption("cookie") } DataFlow::Node getCookieFlagValue(string flag) { From 5cae3005f39b73ec67363eae15f1119b27ceb917 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:20:22 +0200 Subject: [PATCH 038/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 85d36daa6bd..f5abeb1aab4 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -44,7 +44,7 @@ module InsecureCookie { result = this.getOption("cookie") } - DataFlow::Node getCookieFlagValue(string flag) { + private DataFlow::Node getCookieFlagValue(string flag) { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } From e46301475915102e52443e9a67abbb3ba617fd01 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:21:56 +0200 Subject: [PATCH 039/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index f5abeb1aab4..6c3188208e4 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -48,8 +48,10 @@ module InsecureCookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - // A cookie is insecure if the `secure` flag is explicitly set to `false`. - override predicate isInsecure() { getCookieFlagValue(flag()).mayHaveBooleanValue(false) } + override predicate isInsecure() { + // A cookie is insecure if the `secure` flag is explicitly set to `false`. + getCookieFlagValue(flag()).mayHaveBooleanValue(false) + } } /** From fb3ffb895a841e55693804ed34032b99eb54d695 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:23:17 +0200 Subject: [PATCH 040/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 6c3188208e4..23a6f83cb18 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -56,8 +56,6 @@ module InsecureCookie { /** * A cookie set using the `express` module `express-session` (https://github.com/expressjs/session). - * The flag `secure` is not set by default (https://github.com/expressjs/session#cookiesecure). - * The default value for cookie options is { path: '/', httpOnly: true, secure: false, maxAge: null }. */ class InsecureExpressSessionCookie extends ExpressLibraries::ExpressSession::MiddlewareInstance, InsecureCookies { From 97f039af3adc79c220a5fff032d84c4d360be5e2 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:25:11 +0200 Subject: [PATCH 041/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 23a6f83cb18..71be1311cc5 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -62,7 +62,7 @@ module InsecureCookie { override string getKind() { result = "express-session" } override DataFlow::SourceNode getCookieOptionsArgument() { - result = this.getOption("cookie").(DataFlow::SourceNode) + result = this.getOption("cookie") } DataFlow::Node getCookieFlagValue(string flag) { From 40e101de5af10c36853484fa895728f382bd0948 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:26:15 +0200 Subject: [PATCH 042/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 71be1311cc5..7c9168f02cc 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -65,7 +65,7 @@ module InsecureCookie { result = this.getOption("cookie") } - DataFlow::Node getCookieFlagValue(string flag) { + private DataFlow::Node getCookieFlagValue(string flag) { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } From ab128f71728a353d832c13f9a4e96e267febf3cf Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:27:26 +0200 Subject: [PATCH 043/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 7c9168f02cc..e4aca8fac32 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -69,8 +69,8 @@ module InsecureCookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. override predicate isInsecure() { + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. not exists(DataFlow::SourceNode cookieOptions | cookieOptions = this.getCookieOptionsArgument() and getCookieFlagValue(flag()).mayHaveBooleanValue(true) From 9292e3b80e0e1c81cd30da93d0772994a54e738b Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:28:39 +0200 Subject: [PATCH 044/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index e4aca8fac32..e4edf7351f1 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -71,10 +71,7 @@ module InsecureCookie { override predicate isInsecure() { // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - not exists(DataFlow::SourceNode cookieOptions | - cookieOptions = this.getCookieOptionsArgument() and - getCookieFlagValue(flag()).mayHaveBooleanValue(true) - ) and + not getCookieFlagValue(flag()).mayHaveBooleanValue(true) and not getCookieFlagValue(flag()).mayHaveStringValue("auto") } } From 275b8dfda2e16047b31251c7317f2442df0cc630 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:29:36 +0200 Subject: [PATCH 045/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index e4edf7351f1..b84a2500f5c 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -81,7 +81,7 @@ module InsecureCookie { */ class InsecureExpressCookieResponse extends InsecureCookies { InsecureExpressCookieResponse() { - this = any(Express::ResponseExpr response).flow().getALocalSource().getAMemberCall("cookie") + this = any(Express::ResponseExpr response).flow().getALocalSource().getAMethodCall("cookie") } override string getKind() { result = "response.cookie" } From 14c8e4ce768fc48c5578084b01c731537ce5e4d3 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:30:45 +0200 Subject: [PATCH 046/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index b84a2500f5c..3ca117df3c0 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -90,7 +90,7 @@ module InsecureCookie { result = this.(DataFlow::InvokeNode).getLastArgument().getALocalSource() } - DataFlow::Node getCookieFlagValue(string flag) { + private DataFlow::Node getCookieFlagValue(string flag) { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } From a2e945645022db47e7c152a97d46f6bdedba1ce1 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:31:21 +0200 Subject: [PATCH 047/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 3ca117df3c0..0a9170fabf8 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -94,8 +94,9 @@ module InsecureCookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. override predicate isInsecure() { + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + not exists(DataFlow::SourceNode cookieOptions | cookieOptions = this.getCookieOptionsArgument() and getCookieFlagValue(flag()).mayHaveBooleanValue(true) From bfef84e1b57983ef7fc950ba72af6a737d3fad81 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:32:05 +0200 Subject: [PATCH 048/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 0a9170fabf8..36dfd34f1e6 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -97,10 +97,7 @@ module InsecureCookie { override predicate isInsecure() { // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - not exists(DataFlow::SourceNode cookieOptions | - cookieOptions = this.getCookieOptionsArgument() and - getCookieFlagValue(flag()).mayHaveBooleanValue(true) - ) + not getCookieFlagValue(flag()).mayHaveBooleanValue(true) } } From ab20beba565c5de0ac2a2d9dc09eecd82b3d0e77 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:32:51 +0200 Subject: [PATCH 049/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 36dfd34f1e6..79b604f5d63 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -115,8 +115,8 @@ module InsecureCookie { result.asExpr() = this.asExpr().(ArrayExpr).getAnElement() } - // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. override predicate isInsecure() { + // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. not exists(string s | getCookieOptionsArgument().mayHaveStringValue(s) and s.matches("%; secure%") From 05ffd672d70635d2b07330996d814f14ee005945 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:33:38 +0200 Subject: [PATCH 050/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 79b604f5d63..389137f17a3 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -144,8 +144,8 @@ module InsecureCookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. override predicate isInsecure() { + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. not exists(DataFlow::SourceNode cookieOptions | cookieOptions = this.getCookieOptionsArgument() and getCookieFlagValue(flag()).mayHaveBooleanValue(true) From 1ba39e4130e6d1fc190f4e11d19161ad8f638e72 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:34:19 +0200 Subject: [PATCH 051/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 389137f17a3..31f8dc9e93b 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -146,10 +146,7 @@ module InsecureCookie { override predicate isInsecure() { // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - not exists(DataFlow::SourceNode cookieOptions | - cookieOptions = this.getCookieOptionsArgument() and - getCookieFlagValue(flag()).mayHaveBooleanValue(true) - ) + not getCookieFlagValue(flag()).mayHaveBooleanValue(true) } } } From e2908026c556bb2ec89c25b4c21d0f51bd45410d Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:41:55 +0200 Subject: [PATCH 052/146] Remove redundancy --- .../Security/CWE-614/InsecureCookie.qll | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 31f8dc9e93b..fa7a149b518 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -36,21 +36,17 @@ module InsecureCookie { */ class InsecureCookieSession extends ExpressLibraries::CookieSession::MiddlewareInstance, InsecureCookies { - InsecureCookieSession() { this instanceof ExpressLibraries::CookieSession::MiddlewareInstance } - override string getKind() { result = "cookie-session" } - override DataFlow::SourceNode getCookieOptionsArgument() { - result = this.getOption("cookie") - } + override DataFlow::SourceNode getCookieOptionsArgument() { result = this.getOption("cookie") } private DataFlow::Node getCookieFlagValue(string flag) { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - override predicate isInsecure() { - // A cookie is insecure if the `secure` flag is explicitly set to `false`. - getCookieFlagValue(flag()).mayHaveBooleanValue(false) + override predicate isInsecure() { + // A cookie is insecure if the `secure` flag is explicitly set to `false`. + getCookieFlagValue(flag()).mayHaveBooleanValue(false) } } @@ -61,16 +57,14 @@ module InsecureCookie { InsecureCookies { override string getKind() { result = "express-session" } - override DataFlow::SourceNode getCookieOptionsArgument() { - result = this.getOption("cookie") - } + override DataFlow::SourceNode getCookieOptionsArgument() { result = this.getOption("cookie") } private DataFlow::Node getCookieFlagValue(string flag) { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } override predicate isInsecure() { - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. not getCookieFlagValue(flag()).mayHaveBooleanValue(true) and not getCookieFlagValue(flag()).mayHaveStringValue("auto") } @@ -95,9 +89,8 @@ module InsecureCookie { } override predicate isInsecure() { - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - - not getCookieFlagValue(flag()).mayHaveBooleanValue(true) + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + not getCookieFlagValue(flag()).mayHaveBooleanValue(true) } } @@ -116,7 +109,7 @@ module InsecureCookie { } override predicate isInsecure() { - // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. + // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. not exists(string s | getCookieOptionsArgument().mayHaveStringValue(s) and s.matches("%; secure%") @@ -145,7 +138,7 @@ module InsecureCookie { } override predicate isInsecure() { - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. + // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. not getCookieFlagValue(flag()).mayHaveBooleanValue(true) } } From d4b231b86796ba2ed1572aaf9a07b082832ce357 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:48:26 +0200 Subject: [PATCH 053/146] Replace regex --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index fa7a149b518..72d1c1bb951 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -112,7 +112,7 @@ module InsecureCookie { // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. not exists(string s | getCookieOptionsArgument().mayHaveStringValue(s) and - s.matches("%; secure%") + s.regexpMatch("(.*;)?\\s*secure.*") ) } } From 91d44854c07c42a666e7996fae85618bb4241f05 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:53:31 +0200 Subject: [PATCH 054/146] Replace class and module name --- .../Security/CWE-614/InsecureCookie.ql | 4 ++-- .../Security/CWE-614/InsecureCookie.qll | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 228a38d25fa..e45777405f2 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -11,9 +11,9 @@ */ import javascript -import InsecureCookie::InsecureCookie +import InsecureCookie::Cookie -from InsecureCookies insecureCookies +from Cookie insecureCookies where insecureCookies.isInsecure() select "Cookie is added to response without the 'secure' flag being set to true (using " + insecureCookies.getKind() + ").", insecureCookies diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 72d1c1bb951..3bedfbcea40 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -5,7 +5,7 @@ import javascript -module InsecureCookie { +module Cookie { /** * `secure` property of the cookie options. */ @@ -14,7 +14,7 @@ module InsecureCookie { /** * Abstract class to represent different cases of insecure cookie settings. */ - abstract class InsecureCookies extends DataFlow::Node { + abstract class Cookie extends DataFlow::Node { /** * Gets the name of the middleware/library used to set the cookie. */ @@ -34,8 +34,7 @@ module InsecureCookie { /** * A cookie set using the `express` module `cookie-session` (https://github.com/expressjs/cookie-session). */ - class InsecureCookieSession extends ExpressLibraries::CookieSession::MiddlewareInstance, - InsecureCookies { + class InsecureCookieSession extends ExpressLibraries::CookieSession::MiddlewareInstance, Cookie { override string getKind() { result = "cookie-session" } override DataFlow::SourceNode getCookieOptionsArgument() { result = this.getOption("cookie") } @@ -54,7 +53,7 @@ module InsecureCookie { * A cookie set using the `express` module `express-session` (https://github.com/expressjs/session). */ class InsecureExpressSessionCookie extends ExpressLibraries::ExpressSession::MiddlewareInstance, - InsecureCookies { + Cookie { override string getKind() { result = "express-session" } override DataFlow::SourceNode getCookieOptionsArgument() { result = this.getOption("cookie") } @@ -73,7 +72,7 @@ module InsecureCookie { /** * A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie). */ - class InsecureExpressCookieResponse extends InsecureCookies { + class InsecureExpressCookieResponse extends Cookie { InsecureExpressCookieResponse() { this = any(Express::ResponseExpr response).flow().getALocalSource().getAMethodCall("cookie") } @@ -97,7 +96,7 @@ module InsecureCookie { /** * A cookie set using `Set-Cookie` header of an `HTTP` response (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie). */ - class InsecureSetCookieHeader extends InsecureCookies { + class InsecureSetCookieHeader extends Cookie { InsecureSetCookieHeader() { this.asExpr() = any(HTTP::SetCookieHeader setCookie).getHeaderArgument() } @@ -120,7 +119,7 @@ module InsecureCookie { /** * A cookie set using `js-cookie` library (https://github.com/js-cookie/js-cookie). */ - class InsecureJsCookie extends InsecureCookies { + class InsecureJsCookie extends Cookie { InsecureJsCookie() { this = DataFlow::globalVarRef("Cookie").getAMemberCall("set") or this = DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict").getAMemberCall("set") or From 2a322976c62a45a9f5f68337bb25ab395236288d Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:57:04 +0200 Subject: [PATCH 055/146] Changed .qhelp --- .../Security/CWE-614/InsecureCookie.qhelp | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp index cff9e878e59..06e920b44bf 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qhelp @@ -12,64 +12,6 @@ This makes it easier for an attacker to intercept.

    to an HTTP response (if the default value is `false`).

    - - -

    In the first example the `secure` flag is set to `false` using the express middleware `cookie-session`. -In the second example the `secure` flag is set to `true` (it is set `false` by default for HTTP, `true` by default for HTTPS).

    - - - - -
    - - - -

    The first four examples show four ways of adding a cookie using the express middleware `express-session`. -Since the default value for the flag `secure` is false, each example shows a possible scenario where a cookie is set with -the `secure` to `false`. -In the last example the `secure` flag is set to `true`.

    - - - - - - - -
    - - - -

    The first two examples show two ways of adding a cookie using the method `response.cookie`. -In both cases the `secure` flag is to `false`. -In the last example the `secure` flag is set to `true`.

    - - - - - -
    - - - - -

    The first example shows when the `secure` flag is set using the method `Set-Cookie` header of an `HTTP` response. -In this case the `secure` flag is not set. -In the last example the `secure` flag is set.

    - - - - -
    - - - -

    In the first example the `secure` flag is set to `false` using the `js-cookie` library. -In the second example the `secure` flag is set to `true`.

    - - - - -
    From 3e9142bf7187c6ecfff8182c78c443ca0840784c Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 14:58:37 +0200 Subject: [PATCH 056/146] Remove examples --- .../CWE-614/examples/cookie-session_bad.js | 17 ----------------- .../CWE-614/examples/cookie-session_good.js | 17 ----------------- .../examples/express-session_bad1_false.js | 7 ------- .../examples/express-session_bad2_notSet.js | 7 ------- .../examples/express-session_bad3_setEmpty.js | 7 ------- .../CWE-614/examples/express-session_bad4.js | 9 --------- .../CWE-614/examples/express-session_good.js | 9 --------- .../examples/express_response-cookie_bad1.js | 12 ------------ .../examples/express_response-cookie_bad2.js | 12 ------------ .../examples/express_response-cookie_good1.js | 12 ------------ .../Security/CWE-614/examples/httpserver_bad.js | 8 -------- .../CWE-614/examples/httpserver_good.js | 8 -------- .../Security/CWE-614/examples/jsCookie_bad.js | 2 -- .../Security/CWE-614/examples/jsCookie_good.js | 2 -- 14 files changed, 129 deletions(-) delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js delete mode 100644 javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js b/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js deleted file mode 100644 index 009ef60fde3..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_bad.js +++ /dev/null @@ -1,17 +0,0 @@ -const session = require('cookie-session') -const express = require('express') -const app = express() - -const expiryDate = new Date(Date.now() + 60 * 60 * 1000) - -app.use(session({ - name: 'session', - keys: ['key1', 'key2'], - cookie: { - secure: false, // BAD - httpOnly: true, - domain: 'example.com', - path: 'foo/bar', - expires: expiryDate - } -})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js deleted file mode 100644 index b16458d2edf..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/cookie-session_good.js +++ /dev/null @@ -1,17 +0,0 @@ -const session = require('cookie-session') -const express = require('express') -const app = express() - -const expiryDate = new Date(Date.now() + 60 * 60 * 1000) - -app.use(session({ - name: 'session', - keys: ['key1', 'key2'], - cookie: { - secure: true, // GOOD: false by default for HTTP, true by default for HTTPS - httpOnly: true, - domain: 'example.com', - path: 'foo/bar', - expires: expiryDate - } -})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js deleted file mode 100644 index 02868dee748..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad1_false.js +++ /dev/null @@ -1,7 +0,0 @@ -const app = express() -const session = require('express-session') - -app.use(session({ - secret: 'secret', - cookie: { secure: false } // BAD -})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js deleted file mode 100644 index d7b1841b542..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad2_notSet.js +++ /dev/null @@ -1,7 +0,0 @@ -const app = express() -const session = require('express-session') - -app.use(session({ - secret: 'secret' - // BAD: in this case the default value of `secure` flag is `false` -})) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js deleted file mode 100644 index 0ec001ec4fb..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad3_setEmpty.js +++ /dev/null @@ -1,7 +0,0 @@ -const app = express() -const session = require('express-session') - -app.use(session({ - secret: 'secret', - cookie: {} // BAD: in this case the default value of `secure` flag is `false` -})) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js deleted file mode 100644 index 0b0f5cd328d..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_bad4.js +++ /dev/null @@ -1,9 +0,0 @@ -const app = express() -const session = require('express-session') - -const sess = { - secret: 'secret', - cookie: { secure: false } // BAD -} - -app.use(session(sess)) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js deleted file mode 100644 index ae2a7f41f55..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express-session_good.js +++ /dev/null @@ -1,9 +0,0 @@ -const app = express() -const session = require('express-session') - -app.set('trust proxy', 1) - -app.use(session({ - secret: 'secret', - cookie: { secure: true } // GOOD -})) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js deleted file mode 100644 index 1a762c27a2c..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad1.js +++ /dev/null @@ -1,12 +0,0 @@ -const express = require('express') -const app = express() - -app.get('/', function (req, res, next) { - res.cookie('name', 'value', - { - maxAge: 9000000000, - httpOnly: true, - secure: false // BAD - }); - res.end('ok') -}) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js deleted file mode 100644 index ba67049f167..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_bad2.js +++ /dev/null @@ -1,12 +0,0 @@ -const express = require('express') -const app = express() - -app.get('/', function (req, res, next) { - let options = { - maxAge: 9000000000, - httpOnly: true, - secure: false // BAD - } - res.cookie('name', 'value', options); - res.end('ok') -}) diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js b/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js deleted file mode 100644 index ee5fe440b93..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/express_response-cookie_good1.js +++ /dev/null @@ -1,12 +0,0 @@ -const express = require('express') -const app = express() - -app.get('/', function (req, res, next) { - res.cookie('name', 'value', - { - maxAge: 9000000000, - httpOnly: true, - secure: true // GOOD - }); - res.end('ok') -}) \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js b/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js deleted file mode 100644 index dfd2c4bb409..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_bad.js +++ /dev/null @@ -1,8 +0,0 @@ -const http = require('http'); -const server = http.createServer((req, res) => { - res.setHeader('Content-Type', 'text/html'); - // BAD - res.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]); - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.end('ok'); -}); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js deleted file mode 100644 index 8f607aaf972..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/httpserver_good.js +++ /dev/null @@ -1,8 +0,0 @@ -const http = require('http'); -const server = http.createServer((req, res) => { - res.setHeader('Content-Type', 'text/html'); - // GOOD - res.setHeader("Set-Cookie", ["type=ninja; Secure", "language=javascript; secure"]); - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.end('ok'); -}); \ No newline at end of file diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js b/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js deleted file mode 100644 index 6ab10c64e26..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_bad.js +++ /dev/null @@ -1,2 +0,0 @@ -const js_cookie = require('js-cookie') -js_cookie.set('key', 'value', { secure: false }); // BAD diff --git a/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js b/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js deleted file mode 100644 index b18c476b2f5..00000000000 --- a/javascript/ql/src/experimental/Security/CWE-614/examples/jsCookie_good.js +++ /dev/null @@ -1,2 +0,0 @@ -const js_cookie = require('js-cookie') -js_cookie.set('key', 'value', { secure: true }); From 5d6e6be4e45033c5e90770ba489350417085bc1e Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 15:02:52 +0200 Subject: [PATCH 057/146] Add query-tests --- .../Security/CWE-614/InsecureCookies.expected | 9 +++++ .../Security/CWE-614/InsecureCookies.qlref | 1 + .../Security/CWE-614/test_cookie-session.js | 28 ++++++++++++++++ .../Security/CWE-614/test_express-session.js | 33 +++++++++++++++++++ .../Security/CWE-614/test_httpserver.js | 22 +++++++++++++ .../Security/CWE-614/test_jscookie.js | 3 ++ .../Security/CWE-614/test_responseCookie.js | 33 +++++++++++++++++++ 7 files changed, 129 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_cookie-session.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_express-session.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_httpserver.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_jscookie.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-614/test_responseCookie.js diff --git a/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected b/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected new file mode 100644 index 00000000000..de25e9b58ed --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected @@ -0,0 +1,9 @@ +| Cookie is added to response without the 'secure' flag being set to true (using cookie-session). | test_cookie-session.js:18:9:28:2 | session ... }\\n}) | +| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:5:9:8:2 | session ... T OK\\n}) | +| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:10:9:13:2 | session ... T OK\\n}) | +| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:15:9:18:2 | session ... T OK\\n}) | +| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:25:9:25:21 | session(sess) | +| Cookie is added to response without the 'secure' flag being set to true (using js-cookie). | test_jscookie.js:2:1:2:48 | js_cook ... alse }) | +| Cookie is added to response without the 'secure' flag being set to true (using response.cookie). | test_responseCookie.js:5:5:10:10 | res.coo ... }) | +| Cookie is added to response without the 'secure' flag being set to true (using response.cookie). | test_responseCookie.js:20:5:20:40 | res.coo ... ptions) | +| Cookie is added to response without the 'secure' flag being set to true (using set-cookie header). | test_httpserver.js:7:37:7:73 | ["type= ... cript"] | diff --git a/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.qlref b/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.qlref new file mode 100644 index 00000000000..378d5dcae1a --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-614/InsecureCookie.ql diff --git a/javascript/ql/test/query-tests/Security/CWE-614/test_cookie-session.js b/javascript/ql/test/query-tests/Security/CWE-614/test_cookie-session.js new file mode 100644 index 00000000000..d8d80b0059e --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/test_cookie-session.js @@ -0,0 +1,28 @@ +const express = require('express') +const app = express() +const session = require('cookie-session') +const expiryDate = new Date(Date.now() + 60 * 60 * 1000) + +app.use(session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: true, // OK + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate + } +})) + +app.use(session({ + name: 'session', + keys: ['key1', 'key2'], + cookie: { + secure: false, // NOT OK + httpOnly: true, + domain: 'example.com', + path: 'foo/bar', + expires: expiryDate + } +})) diff --git a/javascript/ql/test/query-tests/Security/CWE-614/test_express-session.js b/javascript/ql/test/query-tests/Security/CWE-614/test_express-session.js new file mode 100644 index 00000000000..873fe2162ca --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/test_express-session.js @@ -0,0 +1,33 @@ +const express = require('express') +const app = express() +const session = require('express-session') + +app.use(session({ + secret: 'secret', + cookie: { secure: false } // NOT OK +})) + +app.use(session({ + secret: 'secret' + // NOT OK +})) + +app.use(session({ + secret: 'secret', + cookie: {} // NOT OK +})) + +const sess = { + secret: 'secret', + cookie: { secure: false } // NOT OK +} + +app.use(session(sess)) + + +app.set('trust proxy', 1) +app.use(session({ + secret: 'secret', + cookie: { secure: true } // OK +})) + diff --git a/javascript/ql/test/query-tests/Security/CWE-614/test_httpserver.js b/javascript/ql/test/query-tests/Security/CWE-614/test_httpserver.js new file mode 100644 index 00000000000..fb9fd386850 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/test_httpserver.js @@ -0,0 +1,22 @@ +const http = require('http'); + +function test1() { + const server = http.createServer((req, res) => { + res.setHeader('Content-Type', 'text/html'); + // NOT OK + res.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('ok'); + }); +} + + +function test2() { + const server = http.createServer((req, res) => { + res.setHeader('Content-Type', 'text/html'); + // OK + res.setHeader("Set-Cookie", ["type=ninja; Secure", "language=javascript; secure"]); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('ok'); + }); +} diff --git a/javascript/ql/test/query-tests/Security/CWE-614/test_jscookie.js b/javascript/ql/test/query-tests/Security/CWE-614/test_jscookie.js new file mode 100644 index 00000000000..d53fcecf84b --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/test_jscookie.js @@ -0,0 +1,3 @@ +const js_cookie = require('js-cookie') +js_cookie.set('key', 'value', { secure: false }); // NOT OK +js_cookie.set('key', 'value', { secure: true }); // OK diff --git a/javascript/ql/test/query-tests/Security/CWE-614/test_responseCookie.js b/javascript/ql/test/query-tests/Security/CWE-614/test_responseCookie.js new file mode 100644 index 00000000000..8d002d594f3 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-614/test_responseCookie.js @@ -0,0 +1,33 @@ +const express = require('express') +const app = express() + +app.get('/a', function (req, res, next) { + res.cookie('name', 'value', + { + maxAge: 9000000000, + httpOnly: true, + secure: false // NOT OK + }); + res.end('ok') +}) + +app.get('/b', function (req, res, next) { + let options = { + maxAge: 9000000000, + httpOnly: true, + secure: false // NOT OK + } + res.cookie('name', 'value', options); + res.end('ok') +}) + +app.get('/c', function (req, res, next) { + res.cookie('name', 'value', + { + maxAge: 9000000000, + httpOnly: true, + secure: true // OK + }); + res.end('ok') +}) + From 8ec91ef0c69e7fa51562395a9f6150b6c865bb02 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Sun, 16 Aug 2020 15:23:29 +0200 Subject: [PATCH 058/146] Change polarity predicate isInsecure --- .../Security/CWE-614/InsecureCookie.ql | 6 +-- .../Security/CWE-614/InsecureCookie.qll | 41 ++++++++++--------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index e45777405f2..d08548df993 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -13,7 +13,7 @@ import javascript import InsecureCookie::Cookie -from Cookie insecureCookies -where insecureCookies.isInsecure() +from Cookie cookie +where not cookie.isSecure() select "Cookie is added to response without the 'secure' flag being set to true (using " + - insecureCookies.getKind() + ").", insecureCookies +cookie.getKind() + ").", cookie diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 3bedfbcea40..e43eb61d5f7 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -26,9 +26,9 @@ module Cookie { abstract DataFlow::Node getCookieOptionsArgument(); /** - * Predicate that determines if a cookie is insecure. + * Holds if this cookie is secure. */ - abstract predicate isInsecure(); + abstract predicate isSecure(); } /** @@ -43,9 +43,10 @@ module Cookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - override predicate isInsecure() { - // A cookie is insecure if the `secure` flag is explicitly set to `false`. - getCookieFlagValue(flag()).mayHaveBooleanValue(false) + override predicate isSecure() { + // The flag `secure` is set to `false` by default for HTTP, `true` by default for HTTPS (https://github.com/expressjs/cookie-session#cookie-options). + // A cookie is secure if the `secure` flag is not explicitly set to `false`. + not getCookieFlagValue(flag()).mayHaveBooleanValue(false) } } @@ -62,10 +63,12 @@ module Cookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - override predicate isInsecure() { - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - not getCookieFlagValue(flag()).mayHaveBooleanValue(true) and - not getCookieFlagValue(flag()).mayHaveStringValue("auto") + override predicate isSecure() { + // The flag `secure` is not set by default (https://github.com/expressjs/session#Cookieecure). + // The default value for cookie options is { path: '/', httpOnly: true, secure: false, maxAge: null }. + // A cookie is secure if there are the cookie options with the `secure` flag set to `true` or to `auto`. + getCookieFlagValue(flag()).mayHaveBooleanValue(true) or + getCookieFlagValue(flag()).mayHaveStringValue("auto") } } @@ -87,9 +90,9 @@ module Cookie { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - override predicate isInsecure() { - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - not getCookieFlagValue(flag()).mayHaveBooleanValue(true) + override predicate isSecure() { + // A cookie is secure if there are cookie options with the `secure` flag set to `true`. + getCookieFlagValue(flag()).mayHaveBooleanValue(true) } } @@ -107,9 +110,9 @@ module Cookie { result.asExpr() = this.asExpr().(ArrayExpr).getAnElement() } - override predicate isInsecure() { - // A cookie is insecure if the 'secure' flag is not specified in the cookie definition. - not exists(string s | + override predicate isSecure() { + // A cookie is secure if the 'secure' flag is specified in the cookie definition. + exists(string s | getCookieOptionsArgument().mayHaveStringValue(s) and s.regexpMatch("(.*;)?\\s*secure.*") ) @@ -129,16 +132,16 @@ module Cookie { override string getKind() { result = "js-cookie" } override DataFlow::SourceNode getCookieOptionsArgument() { - result = this.(DataFlow::CallNode).getArgument(2).getALocalSource() + result = this.(DataFlow::CallNode).getAnArgument().getALocalSource() } DataFlow::Node getCookieFlagValue(string flag) { result = this.getCookieOptionsArgument().getAPropertyWrite(flag).getRhs() } - override predicate isInsecure() { - // A cookie is insecure if there are not cookie options with the `secure` flag set to `true`. - not getCookieFlagValue(flag()).mayHaveBooleanValue(true) + override predicate isSecure() { + // A cookie is secure if there are cookie options with the `secure` flag set to `true`. + getCookieFlagValue(flag()).mayHaveBooleanValue(true) } } } From 518459c0f7e29320aaa219923c433d07f20d00d6 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Mon, 17 Aug 2020 10:31:44 +0200 Subject: [PATCH 059/146] Abstract Xss sanitizer Turn the Xss sanitizer into an abstract class to support customizations and provide a default implementation. --- java/ql/src/Security/CWE/CWE-079/XSS.ql | 4 +--- java/ql/src/semmle/code/java/security/XSS.qll | 8 ++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql index 1a1996c5c16..5c29ff51994 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql @@ -22,9 +22,7 @@ class XSSConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } - override predicate isSanitizer(DataFlow::Node node) { - node.getType() instanceof NumericType or node.getType() instanceof BooleanType - } + override predicate isSanitizer(DataFlow::Node node) { node instanceof XssSanitizer } } from DataFlow::PathNode source, DataFlow::PathNode sink, XSSConfig conf diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 84f06f7b41d..34b5e8ba7f4 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -12,6 +12,8 @@ import semmle.code.java.dataflow.TaintTracking2 abstract class XssSink extends DataFlow::Node { } +abstract class XssSanitizer extends DataFlow::Node { } + private class DefaultXssSink extends XssSink { DefaultXssSink() { exists(HttpServletResponseSendErrorMethod m, MethodAccess ma | @@ -80,6 +82,12 @@ private class DefaultXssSink extends XssSink { } } +private class DefaultXSSSanitizer extends XssSanitizer { + DefaultXSSSanitizer() { + this.getType() instanceof NumericType or this.getType() instanceof BooleanType + } +} + private class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration { ServletWriterSourceToWritingMethodFlowConfig() { this = "XSS::ServletWriterSourceToWritingMethodFlowConfig" From 8db5c4f2e2f283c912c0eeee7c9acba615e10118 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Mon, 17 Aug 2020 10:41:27 +0200 Subject: [PATCH 060/146] Abstract additional taint step --- java/ql/src/Security/CWE/CWE-079/XSS.ql | 4 ++++ java/ql/src/semmle/code/java/security/XSS.qll | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/java/ql/src/Security/CWE/CWE-079/XSS.ql b/java/ql/src/Security/CWE/CWE-079/XSS.ql index 5c29ff51994..ae7cec3277d 100644 --- a/java/ql/src/Security/CWE/CWE-079/XSS.ql +++ b/java/ql/src/Security/CWE/CWE-079/XSS.ql @@ -23,6 +23,10 @@ class XSSConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } override predicate isSanitizer(DataFlow::Node node) { node instanceof XssSanitizer } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + any(XssAdditionalTaintStep s).step(node1, node2) + } } from DataFlow::PathNode source, DataFlow::PathNode sink, XSSConfig conf diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 34b5e8ba7f4..ca83f6c4b88 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -14,6 +14,20 @@ abstract class XssSink extends DataFlow::Node { } abstract class XssSanitizer extends DataFlow::Node { } +/** + * A unit class for adding additional taint steps. + * + * Extend this class to add additional taint steps that should apply to the XSS + * taint configuration. + */ +abstract class XssAdditionalTaintStep extends TaintTracking2::Unit { + /** + * Holds if the step from `node1` to `node2` should be considered a taint + * step for all configurations. + */ + abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); +} + private class DefaultXssSink extends XssSink { DefaultXssSink() { exists(HttpServletResponseSendErrorMethod m, MethodAccess ma | From bfdb580206d2e00933488f39cefd493f246ed943 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 17 Aug 2020 11:37:52 +0200 Subject: [PATCH 061/146] Python: Experiemntal cleanup strategy --- .../dataflow/internal/DataFlowPublic.qll | 14 +- .../dataflow/basic/global.expected | 29 ---- .../dataflow/basic/globalStep.expected | 32 ---- .../dataflow/basic/local.expected | 18 +-- .../dataflow/basic/localStep.expected | 4 - .../dataflow/basic/sinks.expected | 12 +- .../dataflow/basic/sources.expected | 12 +- .../consistency/dataflow-consistency.expected | 153 +++++++++++++----- .../dataflow/coverage/localFlow.expected | 3 - 9 files changed, 146 insertions(+), 131 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 0f950dd6052..d03ba150711 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -68,7 +68,7 @@ class EssaNode extends Node, TEssaNode { override Location getLocation() { result = var.getDefinition().getLocation() } } -class CfgNode extends Node, TCfgNode { +abstract class CfgNode extends Node, TCfgNode { ControlFlowNode node; CfgNode() { this = TCfgNode(node) } @@ -83,6 +83,10 @@ class CfgNode extends Node, TCfgNode { override Location getLocation() { result = node.getLocation() } } +class CfgLiteralNode extends CfgNode { + CfgLiteralNode() { node.isLiteral() } +} + /** * An expression, viewed as a node in a data flow graph. * @@ -90,7 +94,13 @@ class CfgNode extends Node, TCfgNode { * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ -class ExprNode extends Node { } +class ExprNode extends CfgNode { + ExprNode() { + // node.isAttribute() + // or + node instanceof NameNode + } +} /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(DataFlowExpr e) { none() } diff --git a/python/ql/test/experimental/dataflow/basic/global.expected b/python/ql/test/experimental/dataflow/basic/global.expected index f42042f7871..73e5e22c98d 100644 --- a/python/ql/test/experimental/dataflow/basic/global.expected +++ b/python/ql/test/experimental/dataflow/basic/global.expected @@ -1,23 +1,12 @@ -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:1:7:1 | GSSA Variable b | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:19:1:19 | SSA variable x | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:1:19:1:19 | SSA variable x | test.py:3:3:3:3 | SSA variable z | @@ -25,37 +14,26 @@ | test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:1:19:1:19 | SSA variable x | test.py:7:1:7:1 | GSSA Variable b | | test.py:1:19:1:19 | SSA variable x | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:2:3:2:3 | SSA variable y | test.py:0:0:0:0 | Exit node for Module test | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | | test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:3:2:3 | SSA variable y | test.py:7:1:7:1 | GSSA Variable b | | test.py:2:3:2:3 | SSA variable y | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:0:0:0:0 | Exit node for Module test | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:7:1:7:1 | GSSA Variable b | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:3:3:3:3 | SSA variable z | test.py:0:0:0:0 | Exit node for Module test | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | test.py:7:1:7:1 | GSSA Variable b | | test.py:3:3:3:3 | SSA variable z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:0:0:0:0 | Exit node for Module test | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:7:1:7:1 | GSSA Variable b | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:4:10:4:10 | ControlFlowNode for z | test.py:0:0:0:0 | Exit node for Module test | | test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:1:7:1 | GSSA Variable b | | test.py:4:10:4:10 | ControlFlowNode for z | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:6:1:6:1 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | -| test.py:6:1:6:1 | GSSA Variable a | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:6:1:6:1 | GSSA Variable a | test.py:1:19:1:19 | SSA variable x | | test.py:6:1:6:1 | GSSA Variable a | test.py:2:3:2:3 | SSA variable y | | test.py:6:1:6:1 | GSSA Variable a | test.py:2:7:2:7 | ControlFlowNode for x | @@ -66,8 +44,6 @@ | test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:6:1:6:1 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | | test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:0:0:0:0 | Exit node for Module test | -| test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:1:19:1:19 | SSA variable x | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:2:3:2:3 | SSA variable y | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:2:7:2:7 | ControlFlowNode for x | @@ -79,12 +55,7 @@ | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:5:7:20 | GSSA Variable a | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:7:19:7:19 | ControlFlowNode for a | -| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | -| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:3:2:3 | SSA variable y | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:2:7:2:7 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected index 9cf3a8c4d89..7e15cd93025 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.expected +++ b/python/ql/test/experimental/dataflow/basic/globalStep.expected @@ -1,25 +1,13 @@ -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:0:0:0:0 | Exit node for Module test | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | | test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | | test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | @@ -40,10 +28,6 @@ | test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | | test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | | test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | @@ -56,10 +40,6 @@ | test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | @@ -76,18 +56,10 @@ | test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | @@ -106,12 +78,8 @@ | test.py:6:1:6:1 | GSSA Variable a | test.py:7:19:7:19 | ControlFlowNode for a | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | | test.py:6:5:6:6 | ControlFlowNode for IntegerLiteral | test.py:6:1:6:1 | GSSA Variable a | -| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:1:7:1 | GSSA Variable b | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:1:7:1 | GSSA Variable b | -| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | -| test.py:7:5:7:20 | GSSA Variable a | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:1:19:1:19 | SSA variable x | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 052c52f90fc..60c9928ebfd 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -1,17 +1,16 @@ -| test.py:0:0:0:0 | Entry node for Module test | test.py:0:0:0:0 | Entry node for Module test | -| test.py:0:0:0:0 | Exit node for Module test | test.py:0:0:0:0 | Exit node for Module test | +| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | -| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | SSA variable $ | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | -| test.py:1:1:1:21 | Entry node for Function obfuscated_id | test.py:1:1:1:21 | Entry node for Function obfuscated_id | -| test.py:1:1:1:21 | Exit node for Function obfuscated_id | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | ControlFlowNode for x | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:1:19:1:19 | SSA variable x | | test.py:1:19:1:19 | SSA variable x | test.py:2:3:2:3 | SSA variable y | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | @@ -19,26 +18,21 @@ | test.py:1:19:1:19 | SSA variable x | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:1:19:1:19 | SSA variable x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:2:3:2:3 | ControlFlowNode for y | test.py:2:3:2:3 | ControlFlowNode for y | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:3:2:3 | SSA variable y | test.py:2:3:2:3 | SSA variable y | | test.py:2:3:2:3 | SSA variable y | test.py:3:3:3:3 | SSA variable z | | test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:3:2:3 | SSA variable y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:2:7:2:7 | ControlFlowNode for x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:7:2:7 | ControlFlowNode for x | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:3:3:3 | SSA variable z | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:3:3:3 | ControlFlowNode for z | test.py:3:3:3:3 | ControlFlowNode for z | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z | test.py:3:3:3:3 | SSA variable z | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:3:7:3:7 | ControlFlowNode for y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:4:10:4:10 | ControlFlowNode for z | -| test.py:4:3:4:10 | ControlFlowNode for Return | test.py:4:3:4:10 | ControlFlowNode for Return | | test.py:4:10:4:10 | ControlFlowNode for z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:6:1:6:1 | ControlFlowNode for a | test.py:6:1:6:1 | ControlFlowNode for a | | test.py:6:1:6:1 | GSSA Variable a | test.py:6:1:6:1 | GSSA Variable a | diff --git a/python/ql/test/experimental/dataflow/basic/localStep.expected b/python/ql/test/experimental/dataflow/basic/localStep.expected index 24509950e88..29510fa4de1 100644 --- a/python/ql/test/experimental/dataflow/basic/localStep.expected +++ b/python/ql/test/experimental/dataflow/basic/localStep.expected @@ -1,9 +1,5 @@ -| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | -| test.py:1:19:1:19 | SSA variable x | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:19:1:19 | SSA variable x | test.py:2:7:2:7 | ControlFlowNode for x | -| test.py:2:3:2:3 | SSA variable y | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:2:3:2:3 | SSA variable y | test.py:3:7:3:7 | ControlFlowNode for y | | test.py:2:7:2:7 | ControlFlowNode for x | test.py:2:3:2:3 | SSA variable y | -| test.py:3:3:3:3 | SSA variable z | test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:3:3:3:3 | SSA variable z | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:3:7:3:7 | ControlFlowNode for y | test.py:3:3:3:3 | SSA variable z | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index bcf55bee27c..9ff2ae53247 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -1,12 +1,13 @@ -| test.py:0:0:0:0 | Entry node for Module test | -| test.py:0:0:0:0 | Exit node for Module test | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | -| test.py:1:1:1:21 | Entry node for Function obfuscated_id | -| test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | @@ -17,7 +18,6 @@ | test.py:3:3:3:3 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:4:3:4:10 | ControlFlowNode for Return | | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:6:1:6:1 | ControlFlowNode for a | | test.py:6:1:6:1 | GSSA Variable a | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index bcf55bee27c..9ff2ae53247 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -1,12 +1,13 @@ -| test.py:0:0:0:0 | Entry node for Module test | -| test.py:0:0:0:0 | Exit node for Module test | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | +| file://:0:0:0:0 | Data flow node | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | -| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | -| test.py:1:1:1:21 | Entry node for Function obfuscated_id | -| test.py:1:1:1:21 | Exit node for Function obfuscated_id | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | @@ -17,7 +18,6 @@ | test.py:3:3:3:3 | ControlFlowNode for z | | test.py:3:3:3:3 | SSA variable z | | test.py:3:7:3:7 | ControlFlowNode for y | -| test.py:4:3:4:10 | ControlFlowNode for Return | | test.py:4:10:4:10 | ControlFlowNode for z | | test.py:6:1:6:1 | ControlFlowNode for a | | test.py:6:1:6:1 | GSSA Variable a | diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index 2ae31eb1126..759c20be6e6 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -1,80 +1,159 @@ uniqueEnclosingCallable -| test.py:0:0:0:0 | Exit node for Module test | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable __name__ | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable __package__ | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable test23 | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | -| test.py:0:0:0:0 | SSA variable $ | Node should have one enclosing callable but has 0. | -| test.py:6:1:6:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:6:5:6:9 | GSSA Variable test1 | Node should have one enclosing callable but has 0. | -| test.py:9:1:9:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:9:5:9:9 | GSSA Variable test2 | Node should have one enclosing callable but has 0. | -| test.py:13:1:13:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:13:5:13:10 | GSSA Variable source | Node should have one enclosing callable but has 0. | -| test.py:16:1:16:14 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:16:5:16:8 | GSSA Variable sink | Node should have one enclosing callable but has 0. | -| test.py:19:1:19:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:19:5:19:9 | GSSA Variable test3 | Node should have one enclosing callable but has 0. | -| test.py:23:1:23:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:23:5:23:9 | GSSA Variable test4 | Node should have one enclosing callable but has 0. | -| test.py:27:1:27:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:27:5:27:9 | GSSA Variable test5 | Node should have one enclosing callable but has 0. | -| test.py:31:1:31:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:31:5:31:9 | GSSA Variable test6 | Node should have one enclosing callable but has 0. | -| test.py:39:1:39:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:39:5:39:9 | GSSA Variable test7 | Node should have one enclosing callable but has 0. | -| test.py:47:1:47:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:47:5:47:11 | GSSA Variable source2 | Node should have one enclosing callable but has 0. | -| test.py:50:1:50:15 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:50:5:50:9 | GSSA Variable sink2 | Node should have one enclosing callable but has 0. | -| test.py:53:1:53:21 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:53:5:53:9 | GSSA Variable sink3 | Node should have one enclosing callable but has 0. | -| test.py:57:1:57:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:57:5:57:9 | GSSA Variable test8 | Node should have one enclosing callable but has 0. | -| test.py:62:1:62:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:62:5:62:9 | GSSA Variable test9 | Node should have one enclosing callable but has 0. | -| test.py:69:1:69:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:69:5:69:10 | GSSA Variable test10 | Node should have one enclosing callable but has 0. | -| test.py:76:1:76:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:76:5:76:7 | GSSA Variable hub | Node should have one enclosing callable but has 0. | -| test.py:79:1:79:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:79:5:79:10 | GSSA Variable test11 | Node should have one enclosing callable but has 0. | -| test.py:84:1:84:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:84:5:84:10 | GSSA Variable test12 | Node should have one enclosing callable but has 0. | -| test.py:89:8:89:13 | ControlFlowNode for ImportExpr | Node should have one enclosing callable but has 0. | | test.py:89:8:89:13 | GSSA Variable module | Node should have one enclosing callable but has 0. | -| test.py:91:1:91:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:91:5:91:10 | GSSA Variable test13 | Node should have one enclosing callable but has 0. | -| test.py:95:1:95:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:95:5:95:10 | GSSA Variable test14 | Node should have one enclosing callable but has 0. | -| test.py:99:1:99:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:99:5:99:10 | GSSA Variable test15 | Node should have one enclosing callable but has 0. | -| test.py:103:1:103:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:103:5:103:10 | GSSA Variable test16 | Node should have one enclosing callable but has 0. | -| test.py:108:1:108:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:108:5:108:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. | -| test.py:118:1:118:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:118:5:118:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. | -| test.py:128:1:128:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:128:5:128:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. | -| test.py:139:20:139:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. | | test.py:139:33:139:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | | test.py:140:1:140:12 | ControlFlowNode for SINK() | Node should have one enclosing callable but has 0. | | test.py:140:1:140:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | | test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. | -| test.py:142:1:142:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:142:5:142:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. | -| test.py:146:1:146:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:146:5:146:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | -| test.py:151:1:151:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:151:5:151:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | -| test.py:161:1:161:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | -| test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | uniqueType uniqueNodeLocation +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | +| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | missingLocation +| Nodes without location: 115 | uniqueNodeToString missingToString parameterCallable diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected index 9e4dc40eafc..54e4a36a7fe 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.expected +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -1,7 +1,4 @@ -| test.py:32:5:32:5 | SSA variable x | test.py:31:1:31:33 | Exit node for Function test_tuple_with_local_flow | | test.py:32:5:32:5 | SSA variable x | test.py:33:9:33:9 | ControlFlowNode for x | | test.py:32:10:32:26 | ControlFlowNode for Tuple | test.py:32:5:32:5 | SSA variable x | | test.py:33:5:33:5 | SSA variable y | test.py:34:5:34:11 | SSA variable y | | test.py:33:5:33:5 | SSA variable y | test.py:34:10:34:10 | ControlFlowNode for y | -| test.py:33:9:33:12 | ControlFlowNode for Subscript | test.py:33:5:33:5 | SSA variable y | -| test.py:34:5:34:11 | SSA variable y | test.py:31:1:31:33 | Exit node for Function test_tuple_with_local_flow | From 894b3f2cd4002d8c5cfef20bf6e5eacc1532f193 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Mon, 17 Aug 2020 11:40:08 +0200 Subject: [PATCH 062/146] Add or change qldocs --- java/ql/src/semmle/code/java/security/XSS.qll | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index ca83f6c4b88..df1a1606f12 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -1,3 +1,5 @@ +/** Provides classes to reason about Cross-site scripting (XSS) vulnerabilities. */ + import java import semmle.code.java.frameworks.Servlets import semmle.code.java.frameworks.android.WebView @@ -6,12 +8,10 @@ import semmle.code.java.frameworks.spring.SpringHttp import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.TaintTracking2 -/* - * Definitions for XSS sinks - */ - +/** A sink that represent a method that outputs data without applying contextual output encoding. */ abstract class XssSink extends DataFlow::Node { } +/** A sanitizer that neutralizes dangerous characters that can be used to perform a XSS attack. */ abstract class XssSanitizer extends DataFlow::Node { } /** @@ -28,6 +28,7 @@ abstract class XssAdditionalTaintStep extends TaintTracking2::Unit { abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); } +/** A default sink representing methods susceptible to XSS attacks. */ private class DefaultXssSink extends XssSink { DefaultXssSink() { exists(HttpServletResponseSendErrorMethod m, MethodAccess ma | @@ -96,12 +97,14 @@ private class DefaultXssSink extends XssSink { } } +/** A default sanitizer that considers numeric and boolean typed data safe for writing to output. */ private class DefaultXSSSanitizer extends XssSanitizer { DefaultXSSSanitizer() { this.getType() instanceof NumericType or this.getType() instanceof BooleanType } } +/** A configuration that tracks data from a servlet writer to an output method. */ private class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration { ServletWriterSourceToWritingMethodFlowConfig() { this = "XSS::ServletWriterSourceToWritingMethodFlowConfig" @@ -116,6 +119,7 @@ private class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking } } +/** A class representing methods that can be used to output data. */ private class WritingMethod extends Method { WritingMethod() { getDeclaringType().getASupertype*().hasQualifiedName("java.io", _) and @@ -127,6 +131,7 @@ private class WritingMethod extends Method { } } +/** A class representing methods that provides access to an output stream or writer. */ class ServletWriterSource extends MethodAccess { ServletWriterSource() { this.getMethod() instanceof ServletResponseGetWriterMethod From 8eacef34678eea61a4bdfbf23652f10e52be26dc Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 17 Aug 2020 12:01:36 +0200 Subject: [PATCH 063/146] Python: Add QL doc --- python/ql/src/semmle/python/Magic.qll | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll index e60b16c16ab..11767254ef0 100644 --- a/python/ql/src/semmle/python/Magic.qll +++ b/python/ql/src/semmle/python/Magic.qll @@ -1,12 +1,33 @@ +/** + * Provides support for magic methods. + * This is done in two steps: + * - A subset of `ControlFlowNode`s are labelled as potentially corresponding to + * a magic method call (by being an instance of `MagicMethod::Potential`). + * - A subset of the potential magic method calls are labelled as being actual + * magic method calls (`MagicMethod::Actual`) if the appropriate method is defined. + */ + import python +/** + * Machinery for detecting magic method calls. + * Extend `MagicMethod::Potential` to capture more cases. + */ module MagicMethod { + /** A control flow node which might correpsond to a magic method call. */ abstract class Potential extends ControlFlowNode { + /** Gets the name of the method that would be called */ abstract string getMagicMethodName(); + + /** Gets the controlflow node that would be passed as the specified argument. */ abstract ControlFlowNode getArg(int n); + + /** Gets the control flow node corresponding to the instance + * that would define the magic method. */ ControlFlowNode getSelf() { result = this.getArg(0) } } + /** A control flow node corresponding to a magic method call. */ class Actual extends ControlFlowNode { Value resolvedMagicMethod; @@ -17,10 +38,12 @@ module MagicMethod { ) } + /** The method that is called. */ Value getResolvedMagicMethod() { result = resolvedMagicMethod } } } +/** A binary expression node that might correspond to a magic method call. */ class MagicBinOp extends MagicMethod::Potential, BinaryExprNode { Operator operator; From a5701db3fafe5fd47201188f067f148e2e9bdfeb Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 17 Aug 2020 15:01:48 +0200 Subject: [PATCH 064/146] Java: Support String.formatted in the format string queries. --- java/ql/src/semmle/code/java/StringFormat.qll | 12 ++++++++++-- java/ql/test/query-tests/StringFormat/A.java | 5 +++++ .../StringFormat/MissingFormatArg.expected | 1 + .../StringFormat/UnusedFormatArg.expected | 1 + java/ql/test/query-tests/StringFormat/options | 1 + 5 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 java/ql/test/query-tests/StringFormat/options diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index fac84c5c8af..69e6d4b056e 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -22,6 +22,7 @@ class StringFormatMethod extends FormatMethod { StringFormatMethod() { ( this.hasName("format") or + this.hasName("formatted") or this.hasName("printf") or this.hasName("readLine") or this.hasName("readPassword") @@ -38,6 +39,8 @@ class StringFormatMethod extends FormatMethod { override int getFormatStringIndex() { result = 0 and this.getSignature() = "format(java.lang.String,java.lang.Object[])" or + result = -1 and this.getSignature() = "formatted(java.lang.Object[])" + or result = 0 and this.getSignature() = "printf(java.lang.String,java.lang.Object[])" or result = 1 and @@ -91,6 +94,11 @@ class FmtSyntax extends TFmtSyntax { predicate isLogger() { this = TFmtLogger() } } +private Expr getArgumentOrQualifier(Call c, int i) { + result = c.getArgument(i) or + result = c.getQualifier() and i = -1 +} + /** * Holds if `c` wraps a call to a `StringFormatMethod`, such that `fmtix` is * the index of the format string argument to `c` and the following and final @@ -111,7 +119,7 @@ private predicate formatWrapper(Callable c, int fmtix, FmtSyntax syntax) { or fmtcall.getCallee().(LoggerFormatMethod).getFormatStringIndex() = i and syntax = TFmtLogger() ) and - fmtcall.getArgument(i) = fmt.getAnAccess() and + getArgumentOrQualifier(fmtcall, i) = fmt.getAnAccess() and fmtcall.getArgument(i + 1) = args.getAnAccess() ) } @@ -155,7 +163,7 @@ class FormattingCall extends Call { } /** Gets the argument to this call in the position of the format string */ - Expr getFormatArgument() { result = this.getArgument(this.getFormatStringIndex()) } + Expr getFormatArgument() { result = getArgumentOrQualifier(this, this.getFormatStringIndex()) } /** Gets an argument to be formatted. */ Expr getAnArgumentToBeFormatted() { diff --git a/java/ql/test/query-tests/StringFormat/A.java b/java/ql/test/query-tests/StringFormat/A.java index 31cba68a622..ff87290bcc9 100644 --- a/java/ql/test/query-tests/StringFormat/A.java +++ b/java/ql/test/query-tests/StringFormat/A.java @@ -85,4 +85,9 @@ public class A { String.format("%s%s", a2); // ok String.format("%s", a2); // unused } + + void formatted() { + "%s%s".formatted(""); // missing + "%s".formatted("", ""); // unused + } } diff --git a/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected b/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected index c88a74338cf..fe2e76dd8fa 100644 --- a/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected +++ b/java/ql/test/query-tests/StringFormat/MissingFormatArg.expected @@ -17,3 +17,4 @@ | A.java:74:5:74:47 | format(...) | This format call refers to 2 argument(s) but only supplies 1 argument(s). | | A.java:79:5:79:31 | format(...) | This format call refers to 3 argument(s) but only supplies 2 argument(s). | | A.java:84:5:84:31 | format(...) | This format call refers to 3 argument(s) but only supplies 2 argument(s). | +| A.java:90:5:90:24 | formatted(...) | This format call refers to 2 argument(s) but only supplies 1 argument(s). | diff --git a/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected b/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected index 2cbe4cc2eb1..b301df54abf 100644 --- a/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected +++ b/java/ql/test/query-tests/StringFormat/UnusedFormatArg.expected @@ -9,3 +9,4 @@ | A.java:76:5:76:57 | format(...) | This format call refers to 2 argument(s) but supplies 3 argument(s). | | A.java:81:5:81:27 | format(...) | This format call refers to 1 argument(s) but supplies 2 argument(s). | | A.java:86:5:86:27 | format(...) | This format call refers to 1 argument(s) but supplies 2 argument(s). | +| A.java:91:5:91:26 | formatted(...) | This format call refers to 1 argument(s) but supplies 2 argument(s). | diff --git a/java/ql/test/query-tests/StringFormat/options b/java/ql/test/query-tests/StringFormat/options new file mode 100644 index 00000000000..266b0eadc5e --- /dev/null +++ b/java/ql/test/query-tests/StringFormat/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 14 -target 14 From 0f87a89fd11782b091a184b795c35978dcd3dc91 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Aug 2020 15:31:41 +0200 Subject: [PATCH 065/146] use typeLabel instead of typeDecl Co-authored-by: Asger F --- .../extractor/src/com/semmle/js/extractor/ASTExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java index 1050590f14d..9d1822dce10 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ASTExtractor.java @@ -1821,7 +1821,7 @@ public class ASTExtractor { Label key = super.visit(nd, c); if (nd.getElementNames() != null) { // Element names are index -1, -2, -3... - visitAll(nd.getElementNames(), key, IdContext.typeDecl, -1, -1); + visitAll(nd.getElementNames(), key, IdContext.typeLabel, -1, -1); } visitAll(nd.getElementTypes(), key, IdContext.typeBind, 0); return key; From 83ed41b24744c98c2dcc696cc40c35038ba9a89c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Aug 2020 15:43:43 +0200 Subject: [PATCH 066/146] move indices comment into plain comment --- javascript/ql/src/semmle/javascript/TypeScript.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 799f386e2a0..02d1c29511a 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -857,10 +857,11 @@ class TupleTypeExpr extends @tupletypeexpr, TypeExpr { /** * Gets the name of the `n`th tuple member, starting at 0. * Only has a result if the tuple members are named. - * - * Type element names are at indices -1, -2, -3, ... */ - Identifier getElementName(int n) { result = getChild(-(n + 1)) and n >= 0 } + Identifier getElementName(int n) { + // Type element names are at indices -1, -2, -3, ... + result = getChild(-(n + 1)) and n >= 0 + } } /** From 73d1fac88ec574644239a4259d6edbd16af32cee Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Mon, 17 Aug 2020 16:20:26 +0200 Subject: [PATCH 067/146] support named tuples where not all tuple elements are named --- .../semmle/js/parser/TypeScriptASTConverter.java | 15 ++++++++------- .../TypeScript/TypeAnnotations/tests.expected | 8 ++++++++ .../TypeScript/TypeAnnotations/tst.ts | 5 +++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java index 8d9079a0b69..91eb2f28646 100644 --- a/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java +++ b/javascript/extractor/src/com/semmle/js/parser/TypeScriptASTConverter.java @@ -2183,14 +2183,15 @@ public class TypeScriptASTConverter { } private Node convertTupleType(JsonObject node, SourceLocation loc) throws ParseError { - List elements = new ArrayList<>(); - ((JsonArray)node.get("elements")).iterator().forEachRemaining(elements::add); + List names = new ArrayList<>(); - List names = convertNodes(elements.stream() - .filter(n -> getKind(n).equals("NamedTupleMember")) - .map(n -> n.getAsJsonObject().get("name")) - .collect(Collectors.toList()) - ); + for (JsonElement element : node.get("elements").getAsJsonArray()) { + Identifier id = null; + if (getKind(element).equals("NamedTupleMember")) { + id = (Identifier)convertNode(element.getAsJsonObject().get("name").getAsJsonObject()); + } + names.add(id); + } return new TupleTypeExpr(loc, convertChildrenAsTypes(node, "elements"), names); } diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected index 9ae9bdfe456..5a0098961bc 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tests.expected @@ -116,6 +116,7 @@ test_VariableTypes | tst.ts:184:7:184:8 | a1 | a1 | tst.ts:184:12:184:17 | number | | tst.ts:185:7:185:8 | a2 | a2 | tst.ts:185:12:185:17 | number | | tst.ts:186:7:186:8 | a3 | a3 | tst.ts:186:12:186:17 | number | +| tst.ts:192:18:192:18 | x | x | tst.ts:192:21:192:43 | [first: ... number] | test_QualifiedTypeAccess | tst.ts:63:19:63:21 | N.I | tst.ts:63:19:63:19 | N | tst.ts:63:21:63:21 | I | | tst.ts:64:20:64:24 | N.M.I | tst.ts:64:20:64:22 | N.M | tst.ts:64:24:64:24 | I | @@ -218,9 +219,15 @@ test_TupleTypeExpr | tst.ts:176:16:176:31 | [number, number] | 1 | 2 | tst.ts:176:25:176:30 | number | | tst.ts:179:21:179:44 | [...Str ... umbers] | 0 | 2 | tst.ts:179:22:179:31 | ...Strings | | tst.ts:179:21:179:44 | [...Str ... umbers] | 1 | 2 | tst.ts:179:34:179:43 | ...Numbers | +| tst.ts:192:21:192:43 | [first: ... number] | 0 | 2 | tst.ts:192:29:192:34 | number | +| tst.ts:192:21:192:43 | [first: ... number] | 1 | 2 | tst.ts:192:37:192:42 | number | +| tst.ts:192:47:192:70 | [number ... number] | 0 | 2 | tst.ts:192:48:192:53 | number | +| tst.ts:192:47:192:70 | [number ... number] | 1 | 2 | tst.ts:192:64:192:69 | number | test_TupleTypeElementName | tst.ts:169:34:169:64 | [first: ... number] | 0 | tst.ts:169:35:169:39 | first | | tst.ts:169:34:169:64 | [first: ... number] | 1 | tst.ts:169:50:169:55 | second | +| tst.ts:192:21:192:43 | [first: ... number] | 0 | tst.ts:192:22:192:26 | first | +| tst.ts:192:47:192:70 | [number ... number] | 1 | tst.ts:192:56:192:61 | second | test_FieldTypes | tst.ts:15:3:15:22 | numberField: number; | tst.ts:15:16:15:21 | number | | tst.ts:16:3:16:22 | stringField: string; | tst.ts:16:16:16:21 | string | @@ -297,6 +304,7 @@ test_ReturnTypes | tst.ts:148:1:152:1 | functio ... ;\\n }\\n} | function assertIsString | tst.ts:148:36:148:56 | asserts ... string | | tst.ts:164:1:166:1 | functio ... rr2];\\n} | function concat | tst.ts:164:66:164:77 | [...T, ...U] | | tst.ts:169:1:172:1 | functio ... + b;\\n} | function labelOnTupleElements | tst.ts:169:68:169:73 | number | +| tst.ts:192:1:194:1 | functio ... rn x;\\n} | function weirdId | tst.ts:192:47:192:70 | [number ... number] | test_KeyofTypeExpr | tst.ts:49:16:49:30 | keyof Interface | tst.ts:49:22:49:30 | Interface | | tst.ts:113:26:113:35 | keyof Node | tst.ts:113:32:113:35 | Node | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts index 138576c4b4f..24a216bb443 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/tst.ts @@ -186,4 +186,9 @@ function shortAssignment() { let a3 : number = a1 ||= a2; let a4 = a2 &&= a3; let a5 = a3 ??= a4; +} + +// only label on some tuple elements (is a type-error) +function weirdId(x: [first: number, number]): [number, second: number] { + return x; } \ No newline at end of file From ca7c045d312b2b1e926800c4afe21429757566ec Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Mon, 17 Aug 2020 16:24:00 +0200 Subject: [PATCH 068/146] Python: bad re match made the tests fail.. --- python/ql/test/experimental/dataflow/coverage/classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 75abe0c82e2..4cc78145fe0 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -8,7 +8,7 @@ # All functions starting with "test_" should run and print `"OK"`. # This can be checked by running validTest.py. -def OK() # Call not found: +def OK(): print("OK") # object.__new__(cls[, ...]) From bbf925fcc4993f16bdfdd4d3cf31a0796af2a060 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 18 Aug 2020 12:56:15 +0200 Subject: [PATCH 069/146] Python: Magic subscript and format (this in preparation for addressing reviews) --- python/ql/src/semmle/python/Magic.qll | 62 +++++++++++++++++-- .../coverage/classesCallGraph.expected | 7 +++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll index 11767254ef0..76d4349c42a 100644 --- a/python/ql/src/semmle/python/Magic.qll +++ b/python/ql/src/semmle/python/Magic.qll @@ -22,8 +22,10 @@ module MagicMethod { /** Gets the controlflow node that would be passed as the specified argument. */ abstract ControlFlowNode getArg(int n); - /** Gets the control flow node corresponding to the instance - * that would define the magic method. */ + /** + * Gets the control flow node corresponding to the instance + * that would define the magic method. + */ ControlFlowNode getSelf() { result = this.getArg(0) } } @@ -47,11 +49,9 @@ module MagicMethod { class MagicBinOp extends MagicMethod::Potential, BinaryExprNode { Operator operator; - MagicBinOp() { this.getOp() = operator} + MagicBinOp() { this.getOp() = operator } - override string getMagicMethodName() { - result = operator.getSpecialMethodName() - } + override string getMagicMethodName() { result = operator.getSpecialMethodName() } override ControlFlowNode getArg(int n) { n = 0 and result = this.getLeft() @@ -59,3 +59,53 @@ class MagicBinOp extends MagicMethod::Potential, BinaryExprNode { n = 1 and result = this.getRight() } } + +/** A subscript expression node that might correspond to a magic method call. */ +abstract class MagicSubscript extends MagicMethod::Potential, SubscriptNode { + override ControlFlowNode getArg(int n) { + n = 0 and result = this.getObject() + or + n = 1 and result = this.getIndex() + } +} + +/** A subscript expression node that might correspond to a call to __getitem__. */ +class MagicGetItem extends MagicSubscript { + MagicGetItem() { this.isLoad() } + + override string getMagicMethodName() { result = "__getitem__" } +} + +/** A subscript expression node that might correspond to a call to __setitem__. */ +class MagicSetItem extends MagicSubscript { + MagicSetItem() { this.isStore() } + + override string getMagicMethodName() { result = "__setitem__" } + + override ControlFlowNode getArg(int n) { + n = 0 and result = this.getObject() + or + n = 1 and result = this.getIndex() + or + n = 2 and result = this.getValueNode() + } + + private ControlFlowNode getValueNode() { + exists(AssignStmt a | + a.getATarget() = this.getNode() and + result.getNode() = a.getValue() + ) + or + exists(AugAssign a | + a.getTarget() = this.getNode() and + result.getNode() = a.getValue() + ) + } +} + +/** A subscript expression node that might correspond to a call to __delitem__. */ +class MagicDelItem extends MagicSubscript { + MagicDelItem() { this.isDelete() } + + override string getMagicMethodName() { result = "__delitem__" } +} diff --git a/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected b/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected index 3a15759e3bd..1c54afef81e 100644 --- a/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected +++ b/python/ql/test/experimental/dataflow/coverage/classesCallGraph.expected @@ -3,6 +3,13 @@ | classes.py:178:7:178:28 | ControlFlowNode for frozenset() | classes.py:178:7:178:28 | ControlFlowNode for frozenset() | | classes.py:182:7:182:26 | ControlFlowNode for dict() | classes.py:182:7:182:26 | ControlFlowNode for dict() | | classes.py:303:28:303:51 | ControlFlowNode for dict() | classes.py:303:28:303:51 | ControlFlowNode for dict() | +| classes.py:428:3:428:14 | ControlFlowNode for with_getitem | classes.py:422:19:422:22 | SSA variable self | +| classes.py:428:16:428:16 | ControlFlowNode for IntegerLiteral | classes.py:422:25:422:27 | SSA variable key | +| classes.py:438:3:438:14 | ControlFlowNode for with_setitem | classes.py:433:19:433:22 | SSA variable self | +| classes.py:438:16:438:16 | ControlFlowNode for IntegerLiteral | classes.py:433:25:433:27 | SSA variable key | +| classes.py:438:21:438:22 | ControlFlowNode for Str | classes.py:433:30:433:34 | SSA variable value | +| classes.py:448:7:448:18 | ControlFlowNode for with_delitem | classes.py:443:19:443:22 | SSA variable self | +| classes.py:448:20:448:20 | ControlFlowNode for IntegerLiteral | classes.py:443:25:443:27 | SSA variable key | | classes.py:466:12:466:24 | ControlFlowNode for Attribute() | classes.py:466:12:466:24 | ControlFlowNode for Attribute() | | classes.py:505:3:505:10 | ControlFlowNode for with_add | classes.py:499:15:499:18 | SSA variable self | | classes.py:505:14:505:21 | ControlFlowNode for with_add | classes.py:499:21:499:25 | SSA variable other | From 59cee284b5b027647cc23b3a5f557eacad810412 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 18 Aug 2020 12:59:04 +0200 Subject: [PATCH 070/146] Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- .../ql/src/experimental/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 319bf69a414..790d9de60f1 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -169,7 +169,7 @@ abstract class DataFlowCall extends TDataFlowCall { /** Get the callable to which this call goes. */ abstract DataFlowCallable getCallable(); - /** Get the specified arguemnt to this call. */ + /** Get the specified argument to this call. */ abstract ControlFlowNode getArg(int n); /** Get the control flow node representing this call. */ From 571520602dfd2ddce58f5a5312a36e41c1def3e0 Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 18 Aug 2020 12:59:20 +0200 Subject: [PATCH 071/146] Update python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- .../ql/src/experimental/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 790d9de60f1..443774b0963 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -180,7 +180,7 @@ abstract class DataFlowCall extends TDataFlowCall { } -/** Represents a call to a callable */ +/** Represents a call to a callable. */ class CallNodeCall extends DataFlowCall, TCallNode { CallNode call; DataFlowCallable callable; From b9bf11adb49739f1c5f5a889aa19806ce5b3e46c Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 18 Aug 2020 12:59:57 +0200 Subject: [PATCH 072/146] Update python/ql/src/semmle/python/Magic.qll Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- python/ql/src/semmle/python/Magic.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll index 76d4349c42a..5ee05f9c622 100644 --- a/python/ql/src/semmle/python/Magic.qll +++ b/python/ql/src/semmle/python/Magic.qll @@ -16,7 +16,7 @@ import python module MagicMethod { /** A control flow node which might correpsond to a magic method call. */ abstract class Potential extends ControlFlowNode { - /** Gets the name of the method that would be called */ + /** Gets the name of the method that would be called. */ abstract string getMagicMethodName(); /** Gets the controlflow node that would be passed as the specified argument. */ From d0eaa139740252814270cb0021adab46f50a45b7 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 18 Aug 2020 14:14:38 +0200 Subject: [PATCH 073/146] Python: Magic -> Special and reaarange classes --- .../dataflow/internal/DataFlowPrivate.qll | 33 +++-- python/ql/src/semmle/python/Magic.qll | 111 ----------------- .../ql/src/semmle/python/SpecialMethods.qll | 117 ++++++++++++++++++ 3 files changed, 133 insertions(+), 128 deletions(-) delete mode 100644 python/ql/src/semmle/python/Magic.qll create mode 100644 python/ql/src/semmle/python/SpecialMethods.qll diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 443774b0963..be29cfb07f1 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -1,6 +1,6 @@ private import python private import DataFlowPublic -import semmle.python.Magic +import semmle.python.SpecialMethods //-------- // Data flow graph @@ -160,7 +160,7 @@ class DataFlowClassValue extends DataFlowCallable, TClassValue { newtype TDataFlowCall = TCallNode(CallNode call) or - TMagicCall(MagicMethod::Actual magic) + TSpecialCall(SpecialMethodCallNode special) abstract class DataFlowCall extends TDataFlowCall { /** Gets a textual representation of this element. */ @@ -179,7 +179,6 @@ abstract class DataFlowCall extends TDataFlowCall { abstract DataFlowCallable getEnclosingCallable(); } - /** Represents a call to a callable. */ class CallNodeCall extends DataFlowCall, TCallNode { CallNode call; @@ -192,9 +191,7 @@ class CallNodeCall extends DataFlowCall, TCallNode { override string toString() { result = call.toString() } - override ControlFlowNode getArg(int n) { - result = call.getArg(n) - } + override ControlFlowNode getArg(int n) { result = call.getArg(n) } override ControlFlowNode getNode() { result = call } @@ -203,22 +200,24 @@ class CallNodeCall extends DataFlowCall, TCallNode { override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() } } -class MagicCall extends DataFlowCall, TMagicCall { - MagicMethod::Actual magic; +class SpecialCall extends DataFlowCall, TSpecialCall { + SpecialMethodCallNode special; - MagicCall() { this = TMagicCall(magic) } + SpecialCall() { this = TSpecialCall(special) } - override string toString() { result = magic.toString() } + override string toString() { result = special.toString() } - override ControlFlowNode getArg(int n) { - result = magic.(MagicMethod::Potential).getArg(n) + override ControlFlowNode getArg(int n) { result = special.(SpecialMethod::Potential).getArg(n) } + + override ControlFlowNode getNode() { result = special } + + override DataFlowCallable getCallable() { + result = TCallableValue(special.getResolvedSpecialMethod()) } - override ControlFlowNode getNode() { result = magic } - - override DataFlowCallable getCallable() { result = TCallableValue(magic.getResolvedMagicMethod()) } - - override DataFlowCallable getEnclosingCallable() { result.getScope() = magic.getNode().getScope() } + override DataFlowCallable getEnclosingCallable() { + result.getScope() = special.getNode().getScope() + } } /** A data flow node that represents a call argument. */ diff --git a/python/ql/src/semmle/python/Magic.qll b/python/ql/src/semmle/python/Magic.qll deleted file mode 100644 index 5ee05f9c622..00000000000 --- a/python/ql/src/semmle/python/Magic.qll +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Provides support for magic methods. - * This is done in two steps: - * - A subset of `ControlFlowNode`s are labelled as potentially corresponding to - * a magic method call (by being an instance of `MagicMethod::Potential`). - * - A subset of the potential magic method calls are labelled as being actual - * magic method calls (`MagicMethod::Actual`) if the appropriate method is defined. - */ - -import python - -/** - * Machinery for detecting magic method calls. - * Extend `MagicMethod::Potential` to capture more cases. - */ -module MagicMethod { - /** A control flow node which might correpsond to a magic method call. */ - abstract class Potential extends ControlFlowNode { - /** Gets the name of the method that would be called. */ - abstract string getMagicMethodName(); - - /** Gets the controlflow node that would be passed as the specified argument. */ - abstract ControlFlowNode getArg(int n); - - /** - * Gets the control flow node corresponding to the instance - * that would define the magic method. - */ - ControlFlowNode getSelf() { result = this.getArg(0) } - } - - /** A control flow node corresponding to a magic method call. */ - class Actual extends ControlFlowNode { - Value resolvedMagicMethod; - - Actual() { - exists(Potential pot | - this.(Potential) = pot and - pot.getSelf().pointsTo().getClass().lookup(pot.getMagicMethodName()) = resolvedMagicMethod - ) - } - - /** The method that is called. */ - Value getResolvedMagicMethod() { result = resolvedMagicMethod } - } -} - -/** A binary expression node that might correspond to a magic method call. */ -class MagicBinOp extends MagicMethod::Potential, BinaryExprNode { - Operator operator; - - MagicBinOp() { this.getOp() = operator } - - override string getMagicMethodName() { result = operator.getSpecialMethodName() } - - override ControlFlowNode getArg(int n) { - n = 0 and result = this.getLeft() - or - n = 1 and result = this.getRight() - } -} - -/** A subscript expression node that might correspond to a magic method call. */ -abstract class MagicSubscript extends MagicMethod::Potential, SubscriptNode { - override ControlFlowNode getArg(int n) { - n = 0 and result = this.getObject() - or - n = 1 and result = this.getIndex() - } -} - -/** A subscript expression node that might correspond to a call to __getitem__. */ -class MagicGetItem extends MagicSubscript { - MagicGetItem() { this.isLoad() } - - override string getMagicMethodName() { result = "__getitem__" } -} - -/** A subscript expression node that might correspond to a call to __setitem__. */ -class MagicSetItem extends MagicSubscript { - MagicSetItem() { this.isStore() } - - override string getMagicMethodName() { result = "__setitem__" } - - override ControlFlowNode getArg(int n) { - n = 0 and result = this.getObject() - or - n = 1 and result = this.getIndex() - or - n = 2 and result = this.getValueNode() - } - - private ControlFlowNode getValueNode() { - exists(AssignStmt a | - a.getATarget() = this.getNode() and - result.getNode() = a.getValue() - ) - or - exists(AugAssign a | - a.getTarget() = this.getNode() and - result.getNode() = a.getValue() - ) - } -} - -/** A subscript expression node that might correspond to a call to __delitem__. */ -class MagicDelItem extends MagicSubscript { - MagicDelItem() { this.isDelete() } - - override string getMagicMethodName() { result = "__delitem__" } -} diff --git a/python/ql/src/semmle/python/SpecialMethods.qll b/python/ql/src/semmle/python/SpecialMethods.qll new file mode 100644 index 00000000000..53206ca657a --- /dev/null +++ b/python/ql/src/semmle/python/SpecialMethods.qll @@ -0,0 +1,117 @@ +/** + * Provides support for special methods. + * This is done in two steps: + * - A subset of `ControlFlowNode`s are labelled as potentially corresponding to + * a special method call (by being an instance of `SpecialMethod::Potential`). + * - A subset of the potential special method calls are labelled as being actual + * special method calls (`SpecialMethodCallNode`) if the appropriate method is defined. + * Extend `SpecialMethod::Potential` to capture more cases. + */ + +import python + + +/** A control flow node which might correpsond to a special method call. */ +class PotentialSpecialMethodCallNode extends ControlFlowNode { + PotentialSpecialMethodCallNode() { this instanceof SpecialMethod::Potential} +} + +/** + * Machinery for detecting special method calls. + * Extend `SpecialMethod::Potential` to capture more cases. + */ +module SpecialMethod { + /** A control flow node which might correpsond to a special method call. */ + abstract class Potential extends ControlFlowNode { + /** Gets the name of the method that would be called. */ + abstract string getSpecialMethodName(); + + /** Gets the controlflow node that would be passed as the specified argument. */ + abstract ControlFlowNode getArg(int n); + + /** + * Gets the control flow node corresponding to the instance + * that would define the special method. + */ + ControlFlowNode getSelf() { result = this.getArg(0) } + } + + /** A binary expression node that might correspond to a special method call. */ + class SpecialBinOp extends Potential, BinaryExprNode { + Operator operator; + + SpecialBinOp() { this.getOp() = operator } + + override string getSpecialMethodName() { result = operator.getSpecialMethodName() } + + override ControlFlowNode getArg(int n) { + n = 0 and result = this.getLeft() + or + n = 1 and result = this.getRight() + } + } + + /** A subscript expression node that might correspond to a special method call. */ + abstract class SpecialSubscript extends Potential, SubscriptNode { + override ControlFlowNode getArg(int n) { + n = 0 and result = this.getObject() + or + n = 1 and result = this.getIndex() + } + } + + /** A subscript expression node that might correspond to a call to __getitem__. */ + class SpecialGetItem extends SpecialSubscript { + SpecialGetItem() { this.isLoad() } + + override string getSpecialMethodName() { result = "__getitem__" } + } + + /** A subscript expression node that might correspond to a call to __setitem__. */ + class SpecialSetItem extends SpecialSubscript { + SpecialSetItem() { this.isStore() } + + override string getSpecialMethodName() { result = "__setitem__" } + + override ControlFlowNode getArg(int n) { + n = 0 and result = this.getObject() + or + n = 1 and result = this.getIndex() + or + n = 2 and result = this.getValueNode() + } + + private ControlFlowNode getValueNode() { + exists(AssignStmt a | + a.getATarget() = this.getNode() and + result.getNode() = a.getValue() + ) + or + exists(AugAssign a | + a.getTarget() = this.getNode() and + result.getNode() = a.getValue() + ) + } + } + + /** A subscript expression node that might correspond to a call to __delitem__. */ + class SpecialDelItem extends SpecialSubscript { + SpecialDelItem() { this.isDelete() } + + override string getSpecialMethodName() { result = "__delitem__" } + } +} + +class SpecialMethodCallNode extends PotentialSpecialMethodCallNode { + Value resolvedSpecialMethod; + + SpecialMethodCallNode() { + exists(SpecialMethod::Potential pot | + this.(SpecialMethod::Potential) = pot and + pot.getSelf().pointsTo().getClass().lookup(pot.getSpecialMethodName()) = resolvedSpecialMethod + ) + } + + /** The method that is called. */ + Value getResolvedSpecialMethod() { result = resolvedSpecialMethod } +} From aab603d26154802a08741e25ec15f82519763702 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 18 Aug 2020 14:37:59 +0200 Subject: [PATCH 074/146] Python: QL doc --- python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index be29cfb07f1..1ca52983b21 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -200,6 +200,7 @@ class CallNodeCall extends DataFlowCall, TCallNode { override DataFlowCallable getEnclosingCallable() { result.getScope() = call.getNode().getScope() } } +/** Represents a call to a special method. */ class SpecialCall extends DataFlowCall, TSpecialCall { SpecialMethodCallNode special; From f8364dc74b085246f17dd87b5909ee4d16c80cf0 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 18 Aug 2020 15:11:20 +0200 Subject: [PATCH 075/146] Python: QL doc --- python/ql/src/semmle/python/SpecialMethods.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/python/ql/src/semmle/python/SpecialMethods.qll b/python/ql/src/semmle/python/SpecialMethods.qll index 53206ca657a..a180ee9253d 100644 --- a/python/ql/src/semmle/python/SpecialMethods.qll +++ b/python/ql/src/semmle/python/SpecialMethods.qll @@ -102,6 +102,7 @@ module SpecialMethod { } } +/** A control flow node corresponding to a special method call. */ class SpecialMethodCallNode extends PotentialSpecialMethodCallNode { Value resolvedSpecialMethod; From de1c75c279a97d7aa6039d208f79522b63f64f7c Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Tue, 18 Aug 2020 16:34:04 +0200 Subject: [PATCH 076/146] Python: QL format --- python/ql/src/semmle/python/SpecialMethods.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/ql/src/semmle/python/SpecialMethods.qll b/python/ql/src/semmle/python/SpecialMethods.qll index a180ee9253d..d7fd44471f8 100644 --- a/python/ql/src/semmle/python/SpecialMethods.qll +++ b/python/ql/src/semmle/python/SpecialMethods.qll @@ -10,10 +10,9 @@ import python - /** A control flow node which might correpsond to a special method call. */ class PotentialSpecialMethodCallNode extends ControlFlowNode { - PotentialSpecialMethodCallNode() { this instanceof SpecialMethod::Potential} + PotentialSpecialMethodCallNode() { this instanceof SpecialMethod::Potential } } /** From 28578fd5721b4ccae192d21efdcd723091ad6743 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 19 Aug 2020 13:12:24 +0200 Subject: [PATCH 077/146] Java: Autoformat. --- java/ql/src/semmle/code/java/StringFormat.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/StringFormat.qll b/java/ql/src/semmle/code/java/StringFormat.qll index 69e6d4b056e..6ac122b58d8 100644 --- a/java/ql/src/semmle/code/java/StringFormat.qll +++ b/java/ql/src/semmle/code/java/StringFormat.qll @@ -95,7 +95,8 @@ class FmtSyntax extends TFmtSyntax { } private Expr getArgumentOrQualifier(Call c, int i) { - result = c.getArgument(i) or + result = c.getArgument(i) + or result = c.getQualifier() and i = -1 } From 18e946d4aae17c30367a66a6dfbba6d1b2f0b61a Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 19 Aug 2020 17:56:02 +0200 Subject: [PATCH 078/146] Python: Small rearrangement --- .../dataflow/internal/DataFlowPrivate.qll | 18 +++ .../dataflow/internal/DataFlowPublic.qll | 20 +-- .../dataflow/basic/local.expected | 6 - .../dataflow/basic/sinks.expected | 6 - .../dataflow/basic/sources.expected | 6 - .../consistency/dataflow-consistency.expected | 116 ------------------ 6 files changed, 23 insertions(+), 149 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index 1f46fd341e9..eeceb673793 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -7,6 +7,24 @@ private import DataFlowPublic //-------- // Nodes //-------- +/** A control flow node which is also a dataflow node */ +abstract class DataFlowCfgNode extends ControlFlowNode { } + +/** Literals contribute to dataflow */ +class CfgLiteralNode extends DataFlowCfgNode { + CfgLiteralNode() { this.isLiteral() } +} + +/** Variables contribute to dataflow */ +class CfgNameNode extends DataFlowCfgNode { + CfgNameNode() { this instanceof NameNode } +} + +/** Calls contribute to dataflow */ +class CfgCallNode extends DataFlowCfgNode { + CfgCallNode() { this instanceof CallNode } +} + /** * A node associated with an object after an operation that might have * changed its state. diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index d03ba150711..12118f75182 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -20,7 +20,7 @@ newtype TNode = /** A node corresponding to an SSA variable. */ TEssaNode(EssaVariable var) or /** A node corresponding to a control flow node. */ - TCfgNode(ControlFlowNode node) + TCfgNode(DataFlowCfgNode node) /** * An element, viewed as a node in a data flow graph. Either an SSA variable @@ -68,12 +68,12 @@ class EssaNode extends Node, TEssaNode { override Location getLocation() { result = var.getDefinition().getLocation() } } -abstract class CfgNode extends Node, TCfgNode { - ControlFlowNode node; +class CfgNode extends Node, TCfgNode { + DataFlowCfgNode node; CfgNode() { this = TCfgNode(node) } - ControlFlowNode getNode() { result = node } + DataFlowCfgNode getNode() { result = node } /** Gets a textual representation of this element. */ override string toString() { result = node.toString() } @@ -83,10 +83,6 @@ abstract class CfgNode extends Node, TCfgNode { override Location getLocation() { result = node.getLocation() } } -class CfgLiteralNode extends CfgNode { - CfgLiteralNode() { node.isLiteral() } -} - /** * An expression, viewed as a node in a data flow graph. * @@ -94,13 +90,7 @@ class CfgLiteralNode extends CfgNode { * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ -class ExprNode extends CfgNode { - ExprNode() { - // node.isAttribute() - // or - node instanceof NameNode - } -} +class ExprNode extends CfgNode { } /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(DataFlowExpr e) { none() } diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 60c9928ebfd..217afdc3185 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -1,9 +1,3 @@ -| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | file://:0:0:0:0 | Data flow node | | test.py:0:0:0:0 | GSSA Variable __name__ | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index 9ff2ae53247..2cd04d0e82c 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -1,9 +1,3 @@ -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index 9ff2ae53247..2cd04d0e82c 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -1,9 +1,3 @@ -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | -| file://:0:0:0:0 | Data flow node | | test.py:0:0:0:0 | GSSA Variable __name__ | | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index 759c20be6e6..f7f7f7a7211 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -37,123 +37,7 @@ uniqueEnclosingCallable | test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. | uniqueType uniqueNodeLocation -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | -| file://:0:0:0:0 | Data flow node | Node should have one location but has 0. | missingLocation -| Nodes without location: 115 | uniqueNodeToString missingToString parameterCallable From 5a734730de1b7a4de1fd479881714a550e9f8869 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 20 Aug 2020 15:00:42 +0200 Subject: [PATCH 079/146] Python: Control flow nodes are dataflow nodes iff they are expression nodes We could refine this later, but it seems to work for now... --- .../dataflow/internal/DataFlowPrivate.qll | 19 +++------- .../dataflow/internal/DataFlowPublic.qll | 6 ++-- .../dataflow/basic/global.expected | 4 +++ .../dataflow/basic/globalStep.expected | 2 ++ .../dataflow/basic/local.expected | 1 + .../dataflow/basic/sinks.expected | 1 + .../dataflow/basic/sources.expected | 1 + .../consistency/dataflow-consistency.expected | 35 +++++++++++++++++++ .../dataflow/coverage/localFlow.expected | 1 + 9 files changed, 53 insertions(+), 17 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index eeceb673793..22e08f1f216 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -7,22 +7,11 @@ private import DataFlowPublic //-------- // Nodes //-------- +predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr } + /** A control flow node which is also a dataflow node */ -abstract class DataFlowCfgNode extends ControlFlowNode { } - -/** Literals contribute to dataflow */ -class CfgLiteralNode extends DataFlowCfgNode { - CfgLiteralNode() { this.isLiteral() } -} - -/** Variables contribute to dataflow */ -class CfgNameNode extends DataFlowCfgNode { - CfgNameNode() { this instanceof NameNode } -} - -/** Calls contribute to dataflow */ -class CfgCallNode extends DataFlowCfgNode { - CfgCallNode() { this instanceof CallNode } +class DataFlowCfgNode extends ControlFlowNode { + DataFlowCfgNode() { isExpressionNode(this) } } /** diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 12118f75182..122ea0ca9fd 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -90,10 +90,12 @@ class CfgNode extends Node, TCfgNode { * to multiple `ExprNode`s, just like it may correspond to multiple * `ControlFlow::Node`s. */ -class ExprNode extends CfgNode { } +class ExprNode extends CfgNode { + ExprNode() { isExpressionNode(node) } +} /** Gets a node corresponding to expression `e`. */ -ExprNode exprNode(DataFlowExpr e) { none() } +ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e } /** * The value of a parameter at function entry, viewed as a node in a data diff --git a/python/ql/test/experimental/dataflow/basic/global.expected b/python/ql/test/experimental/dataflow/basic/global.expected index 73e5e22c98d..4e616d5b6e4 100644 --- a/python/ql/test/experimental/dataflow/basic/global.expected +++ b/python/ql/test/experimental/dataflow/basic/global.expected @@ -4,6 +4,10 @@ | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:1:7:1 | GSSA Variable b | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:1:7:1 | GSSA Variable b | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:1:7:1 | GSSA Variable b | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/globalStep.expected b/python/ql/test/experimental/dataflow/basic/globalStep.expected index 7e15cd93025..58aa95a3621 100644 --- a/python/ql/test/experimental/dataflow/basic/globalStep.expected +++ b/python/ql/test/experimental/dataflow/basic/globalStep.expected @@ -4,6 +4,8 @@ | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:0:0:0:0 | GSSA Variable b | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 217afdc3185..4777c30adfd 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -2,6 +2,7 @@ | test.py:0:0:0:0 | GSSA Variable __package__ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | test.py:1:19:1:19 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index 2cd04d0e82c..8b292d55b5e 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -2,6 +2,7 @@ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index 2cd04d0e82c..8b292d55b5e 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -2,6 +2,7 @@ | test.py:0:0:0:0 | GSSA Variable __package__ | | test.py:0:0:0:0 | GSSA Variable b | | test.py:0:0:0:0 | SSA variable $ | +| test.py:1:1:1:21 | ControlFlowNode for FunctionExpr | | test.py:1:5:1:17 | ControlFlowNode for obfuscated_id | | test.py:1:5:1:17 | GSSA Variable obfuscated_id | | test.py:1:19:1:19 | ControlFlowNode for x | diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index f7f7f7a7211..20054ec34f8 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -5,36 +5,71 @@ uniqueEnclosingCallable | test.py:0:0:0:0 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | | test.py:0:0:0:0 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | +| test.py:6:1:6:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:6:5:6:9 | GSSA Variable test1 | Node should have one enclosing callable but has 0. | +| test.py:9:1:9:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:9:5:9:9 | GSSA Variable test2 | Node should have one enclosing callable but has 0. | +| test.py:13:1:13:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:13:5:13:10 | GSSA Variable source | Node should have one enclosing callable but has 0. | +| test.py:16:1:16:14 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:16:5:16:8 | GSSA Variable sink | Node should have one enclosing callable but has 0. | +| test.py:19:1:19:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:19:5:19:9 | GSSA Variable test3 | Node should have one enclosing callable but has 0. | +| test.py:23:1:23:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:23:5:23:9 | GSSA Variable test4 | Node should have one enclosing callable but has 0. | +| test.py:27:1:27:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:27:5:27:9 | GSSA Variable test5 | Node should have one enclosing callable but has 0. | +| test.py:31:1:31:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:31:5:31:9 | GSSA Variable test6 | Node should have one enclosing callable but has 0. | +| test.py:39:1:39:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:39:5:39:9 | GSSA Variable test7 | Node should have one enclosing callable but has 0. | +| test.py:47:1:47:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:47:5:47:11 | GSSA Variable source2 | Node should have one enclosing callable but has 0. | +| test.py:50:1:50:15 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:50:5:50:9 | GSSA Variable sink2 | Node should have one enclosing callable but has 0. | +| test.py:53:1:53:21 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:53:5:53:9 | GSSA Variable sink3 | Node should have one enclosing callable but has 0. | +| test.py:57:1:57:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:57:5:57:9 | GSSA Variable test8 | Node should have one enclosing callable but has 0. | +| test.py:62:1:62:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:62:5:62:9 | GSSA Variable test9 | Node should have one enclosing callable but has 0. | +| test.py:69:1:69:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:69:5:69:10 | GSSA Variable test10 | Node should have one enclosing callable but has 0. | +| test.py:76:1:76:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:76:5:76:7 | GSSA Variable hub | Node should have one enclosing callable but has 0. | +| test.py:79:1:79:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:79:5:79:10 | GSSA Variable test11 | Node should have one enclosing callable but has 0. | +| test.py:84:1:84:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:84:5:84:10 | GSSA Variable test12 | Node should have one enclosing callable but has 0. | +| test.py:89:8:89:13 | ControlFlowNode for ImportExpr | Node should have one enclosing callable but has 0. | | test.py:89:8:89:13 | GSSA Variable module | Node should have one enclosing callable but has 0. | +| test.py:91:1:91:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:91:5:91:10 | GSSA Variable test13 | Node should have one enclosing callable but has 0. | +| test.py:95:1:95:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:95:5:95:10 | GSSA Variable test14 | Node should have one enclosing callable but has 0. | +| test.py:99:1:99:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:99:5:99:10 | GSSA Variable test15 | Node should have one enclosing callable but has 0. | +| test.py:103:1:103:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:103:5:103:10 | GSSA Variable test16 | Node should have one enclosing callable but has 0. | +| test.py:108:1:108:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:108:5:108:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. | +| test.py:118:1:118:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:118:5:118:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. | +| test.py:128:1:128:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | | test.py:128:5:128:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. | +| test.py:139:20:139:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. | | test.py:139:33:139:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | | test.py:140:1:140:12 | ControlFlowNode for SINK() | Node should have one enclosing callable but has 0. | | test.py:140:1:140:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. | | test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. | +| test.py:142:1:142:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:142:5:142:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. | +| test.py:146:1:146:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:146:5:146:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. | +| test.py:151:1:151:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:151:5:151:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. | +| test.py:161:1:161:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. | +| test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. | uniqueType uniqueNodeLocation missingLocation diff --git a/python/ql/test/experimental/dataflow/coverage/localFlow.expected b/python/ql/test/experimental/dataflow/coverage/localFlow.expected index 54e4a36a7fe..d9306fab9f6 100644 --- a/python/ql/test/experimental/dataflow/coverage/localFlow.expected +++ b/python/ql/test/experimental/dataflow/coverage/localFlow.expected @@ -2,3 +2,4 @@ | test.py:32:10:32:26 | ControlFlowNode for Tuple | test.py:32:5:32:5 | SSA variable x | | test.py:33:5:33:5 | SSA variable y | test.py:34:5:34:11 | SSA variable y | | test.py:33:5:33:5 | SSA variable y | test.py:34:10:34:10 | ControlFlowNode for y | +| test.py:33:9:33:12 | ControlFlowNode for Subscript | test.py:33:5:33:5 | SSA variable y | From 94e6fd9199d118c92a1f80107f1be69690062430 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 20 Aug 2020 15:16:23 +0200 Subject: [PATCH 080/146] Python: Convenience methods asVar, asCfgNode, and asExpr --- .../dataflow/internal/DataFlowPublic.qll | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 122ea0ca9fd..55fe94350cc 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -51,6 +51,15 @@ class Node extends TNode { ) { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } + + /** Convenience method for casting to EssaNode and calling getVar. */ + EssaVariable asVar() { none() } + + /** Convenience method for casting to CfgNode and calling getNode. */ + DataFlowCfgNode asCfgNode() { none() } + + /** Convenience method for casting to ExprNode and calling getNode and getNode again. */ + Expr asExpr() { none() } } class EssaNode extends Node, TEssaNode { @@ -60,6 +69,8 @@ class EssaNode extends Node, TEssaNode { EssaVariable getVar() { result = var } + override EssaVariable asVar() { result = var } + /** Gets a textual representation of this element. */ override string toString() { result = var.toString() } @@ -75,6 +86,8 @@ class CfgNode extends Node, TCfgNode { DataFlowCfgNode getNode() { result = node } + override DataFlowCfgNode asCfgNode() { result = node } + /** Gets a textual representation of this element. */ override string toString() { result = node.toString() } @@ -92,6 +105,8 @@ class CfgNode extends Node, TCfgNode { */ class ExprNode extends CfgNode { ExprNode() { isExpressionNode(node) } + + override Expr asExpr() { result = node.getNode() } } /** Gets a node corresponding to expression `e`. */ From 9cdee63ed7967f32a585f502caac1674ba316ea7 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 19 Aug 2020 14:53:40 +0200 Subject: [PATCH 081/146] C#: Enable nullability checks on Semmle.Extraction.CIL --- .../Semmle.Extraction.CIL/CachedFunction.cs | 2 +- .../Semmle.Extraction.CIL/Context.cs | 23 +- .../Entities/Assembly.cs | 10 +- .../Entities/Attribute.cs | 8 +- .../Semmle.Extraction.CIL/Entities/Event.cs | 2 +- .../Entities/ExceptionRegion.cs | 4 +- .../Semmle.Extraction.CIL/Entities/Field.cs | 4 +- .../Semmle.Extraction.CIL/Entities/File.cs | 10 +- .../Semmle.Extraction.CIL/Entities/Folder.cs | 2 +- .../Entities/Instruction.cs | 17 +- .../Semmle.Extraction.CIL/Entities/Method.cs | 65 ++--- .../Entities/Namespace.cs | 10 +- .../Entities/Parameter.cs | 2 +- .../Entities/Property.cs | 2 +- .../Entities/SourceLocation.cs | 2 +- .../Semmle.Extraction.CIL/Entities/Type.cs | 252 +++++++++++------- .../Semmle.Extraction.CIL/Factories.cs | 2 +- .../PDB/MetadataPdbReader.cs | 8 +- .../PDB/NativePdbReader.cs | 16 +- .../Semmle.Extraction.CIL/PDB/PdbReader.cs | 19 +- .../Semmle.Extraction.CIL.csproj | 1 + .../Semmle.Util/IEnumerableExtensions.cs | 4 +- 22 files changed, 286 insertions(+), 179 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs b/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs index 3bbc386a691..d127addf899 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/CachedFunction.cs @@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL /// /// The type of the source. /// The type of the generated object. - public class CachedFunction + public class CachedFunction where SrcType : notnull { readonly Func generator; readonly Dictionary cache; diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.cs index 79fb8b7a8d4..618293553f0 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.cs @@ -14,13 +14,19 @@ namespace Semmle.Extraction.CIL /// partial class Context : IDisposable { - public Extraction.Context cx; readonly FileStream stream; - public readonly MetadataReader mdReader; - public readonly PEReader peReader; - public readonly string assemblyPath; - public Entities.Assembly assembly; - public PDB.IPdb pdb; + Entities.Assembly? assemblyNull; + + public Extraction.Context cx { get; } + public MetadataReader mdReader { get; } + public PEReader peReader { get; } + public string assemblyPath { get; } + public Entities.Assembly assembly + { + get { return assemblyNull!; } + set { assemblyNull = value; } + } + public PDB.IPdb? pdb { get; } public Context(Extraction.Context cx, string assemblyPath, bool extractPdbs) { @@ -105,7 +111,7 @@ namespace Semmle.Extraction.CIL /// /// The handle of the method. /// The debugging information, or null if the information could not be located. - public PDB.IMethod GetMethodDebugInformation(MethodDefinitionHandle handle) + public PDB.IMethod? GetMethodDebugInformation(MethodDefinitionHandle handle) { return pdb == null ? null : pdb.GetMethod(handle.ToDebugInformationHandle()); } @@ -125,7 +131,8 @@ namespace Semmle.Extraction.CIL } /// - /// The list of generic type parameters. + /// The list of generic type parameters, including type parameters of + /// containing types. /// public abstract IEnumerable TypeParameters { get; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs index 255d37699f2..0368888caa7 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Assembly.cs @@ -47,9 +47,9 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(cx.assemblyPath.Replace("\\", "/")); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return GetType() == obj.GetType() && Equals(file, ((Assembly)obj).file); + return GetType() == obj?.GetType() && Equals(file, ((Assembly)obj).file); } public override int GetHashCode() => 7 * file.GetHashCode(); @@ -63,7 +63,7 @@ namespace Semmle.Extraction.CIL.Entities get { yield return file; - yield return Tuples.assemblies(this, file, FullName, assemblyName.Name, assemblyName.Version.ToString()); + yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty); if (cx.pdb != null) { @@ -75,7 +75,7 @@ namespace Semmle.Extraction.CIL.Entities foreach (var handle in cx.mdReader.TypeDefinitions) { - IExtractionProduct product = null; + IExtractionProduct? product = null; try { product = cx.Create(handle); @@ -92,7 +92,7 @@ namespace Semmle.Extraction.CIL.Entities foreach (var handle in cx.mdReader.MethodDefinitions) { - IExtractionProduct product = null; + IExtractionProduct? product = null; try { product = cx.Create(handle); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs index ed3e866c16f..f1d0a818e07 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Attribute.cs @@ -27,7 +27,7 @@ namespace Semmle.Extraction.CIL.Entities this.@object = @object; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Attribute attribute && handle.Equals(attribute.handle); } @@ -58,13 +58,15 @@ namespace Semmle.Extraction.CIL.Entities for (int index = 0; index < decoded.FixedArguments.Length; ++index) { object value = decoded.FixedArguments[index].Value; - yield return Tuples.cil_attribute_positional_argument(this, index, value == null ? "null" : value.ToString()); + var stringValue = value?.ToString(); + yield return Tuples.cil_attribute_positional_argument(this, index, stringValue ?? "null"); } foreach (var p in decoded.NamedArguments) { object value = p.Value; - yield return Tuples.cil_attribute_named_argument(this, p.Name, value == null ? "null" : value.ToString()); + var stringValue = value?.ToString(); + yield return Tuples.cil_attribute_named_argument(this, p.Name, stringValue ?? "null"); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs index da33b9a63d5..dc3453a786c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Event.cs @@ -36,7 +36,7 @@ namespace Semmle.Extraction.CIL.Entities public override string IdSuffix => ";cil-event"; - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Event e && handle.Equals(e.handle); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs index 57035d993af..260fc3c357f 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/ExceptionRegion.cs @@ -30,7 +30,7 @@ namespace Semmle.Extraction.CIL.Entities { get { - IInstruction try_start, try_end, handler_start; + IInstruction? try_start, try_end, handler_start; if (!jump_table.TryGetValue(r.TryOffset, out try_start)) throw new InternalError("Failed to retrieve handler"); @@ -44,7 +44,7 @@ namespace Semmle.Extraction.CIL.Entities if (r.FilterOffset != -1) { - IInstruction filter_start; + IInstruction? filter_start; if (!jump_table.TryGetValue(r.FilterOffset, out filter_start)) throw new InternalError("ExceptionRegion filter clause"); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs index 400b48fc07e..9e633ef4219 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Field.cs @@ -91,7 +91,7 @@ namespace Semmle.Extraction.CIL.Entities fd = cx.mdReader.GetFieldDefinition(handle); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is DefinitionField field && handle.Equals(field.handle); } @@ -153,7 +153,7 @@ namespace Semmle.Extraction.CIL.Entities declType = (Type)cx.CreateGeneric(gc, mr.Parent); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MemberReferenceField field && Handle.Equals(field.Handle); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs index bc8c4c8c76d..0ff31dcc6f1 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs @@ -25,9 +25,9 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path)); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - return GetType() == obj.GetType() && path == ((File)obj).path; + return GetType() == obj?.GetType() && path == ((File)obj).path; } public override int GetHashCode() => 11 * path.GetHashCode(); @@ -36,7 +36,11 @@ namespace Semmle.Extraction.CIL.Entities { get { - var parent = cx.CreateFolder(System.IO.Path.GetDirectoryName(path)); + var directoryName = System.IO.Path.GetDirectoryName(path); + if (directoryName == null) + throw new InternalError($"Directory name for path '{path}' is null."); + + var parent = cx.CreateFolder(directoryName); yield return parent; yield return Tuples.containerparent(parent, this); yield return Tuples.files(this, path, System.IO.Path.GetFileNameWithoutExtension(path), System.IO.Path.GetExtension(path).Substring(1)); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs index 48ebe6a19d1..b6597a3eba9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Folder.cs @@ -41,7 +41,7 @@ namespace Semmle.Extraction.CIL.Entities } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Folder folder && path == folder.path; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 925dea6e711..1c5607a23ab 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -365,6 +365,11 @@ namespace Semmle.Extraction.CIL.Entities { int offset = Offset; + if (Method.Implementation is null) + { + yield break; + } + yield return Tuples.cil_instruction(this, (int)OpCode, Index, Method.Implementation); switch (PayloadType) @@ -414,11 +419,17 @@ namespace Semmle.Extraction.CIL.Entities break; case Payload.Arg8: case Payload.Arg16: - yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]); + if (!(Method.Parameters is null)) + { + yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]); + } break; case Payload.Local8: case Payload.Local16: - yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]); + if (!(Method.LocalVariables is null)) + { + yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]); + } break; case Payload.None: case Payload.Target8: @@ -439,7 +450,7 @@ namespace Semmle.Extraction.CIL.Entities public IEnumerable JumpContents(Dictionary jump_table) { int target; - IInstruction inst; + IInstruction? inst; switch (PayloadType) { diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index 73fa7712b75..cc9fb49afa9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -23,25 +23,29 @@ namespace Semmle.Extraction.CIL.Entities /// abstract class Method : TypeContainer, IMethod { + protected MethodTypeParameter[]? genericParams; + protected GenericContext gc; + protected MethodSignature signature; + protected Method(GenericContext gc) : base(gc.cx) { this.gc = gc; } - public override IEnumerable TypeParameters => gc.TypeParameters.Concat(declaringType.TypeParameters); + public override IEnumerable TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters); public override IEnumerable MethodParameters => genericParams == null ? gc.MethodParameters : gc.MethodParameters.Concat(genericParams); public int GenericParameterCount => signature.GenericParameterCount; - public virtual Method SourceDeclaration => this; + public virtual Method? SourceDeclaration => this; public abstract Type DeclaringType { get; } public abstract string Name { get; } - public virtual IList LocalVariables => throw new NotImplementedException(); - public IList Parameters { get; private set; } + public virtual IList? LocalVariables => throw new NotImplementedException(); + public IList? Parameters { get; private set; } public override void WriteId(TextWriter trapFile) => WriteMethodId(trapFile, DeclaringType, NameLabel); @@ -70,12 +74,6 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(')'); } - protected MethodTypeParameter[] genericParams; - protected Type declaringType; - protected GenericContext gc; - protected MethodSignature signature; - protected string name; - public override string IdSuffix => ";cil-method"; protected void PopulateParameters(IEnumerable parameterTypes) @@ -145,13 +143,15 @@ namespace Semmle.Extraction.CIL.Entities { readonly Handle handle; readonly MethodDefinition md; - readonly PDB.IMethod methodDebugInformation; + readonly PDB.IMethod? methodDebugInformation; + readonly Type declaringType; - LocalVariable[] locals; + string name; + LocalVariable[]? locals; - public MethodImplementation Implementation { get; private set; } + public MethodImplementation? Implementation { get; private set; } - public override IList LocalVariables => locals; + public override IList? LocalVariables => locals; public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc) { @@ -167,7 +167,7 @@ namespace Semmle.Extraction.CIL.Entities methodDebugInformation = cx.GetMethodDebugInformation(handle); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is DefinitionMethod method && handle.Equals(method.handle); } @@ -208,7 +208,7 @@ namespace Semmle.Extraction.CIL.Entities PopulateParameters(typeSignature.ParameterTypes); - foreach (var c in Parameters) + foreach (var c in Parameters!) yield return c; foreach (var c in PopulateFlags) @@ -315,8 +315,8 @@ namespace Semmle.Extraction.CIL.Entities // The sequence point gives the location of each instruction. // The location of an instruction is given by the sequence point *after* the // instruction. - IEnumerator nextSequencePoint = null; - PdbSourceLocation instructionLocation = null; + IEnumerator? nextSequencePoint = null; + PdbSourceLocation? instructionLocation = null; if (methodDebugInformation != null) { @@ -401,9 +401,9 @@ namespace Semmle.Extraction.CIL.Entities { readonly MemberReferenceHandle handle; readonly MemberReference mr; - readonly Type declType; + readonly Type declaringType; readonly GenericContext parent; - readonly Method sourceDeclaration; + readonly Method? sourceDeclaration; public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc) { @@ -416,22 +416,24 @@ namespace Semmle.Extraction.CIL.Entities parent = (GenericContext)cx.CreateGeneric(gc, mr.Parent); var parentMethod = parent as Method; - nameLabel = cx.GetString(mr.Name); - declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType; + var declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType; if (declType is null) throw new InternalError("Parent context of method is not a type"); - var typeSourceDeclaration = declType.SourceDeclaration; - sourceDeclaration = typeSourceDeclaration == declType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature); + declaringType = declType; + nameLabel = cx.GetString(mr.Name); + + var typeSourceDeclaration = declaringType.SourceDeclaration; + sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature); } private readonly string nameLabel; public override string NameLabel => nameLabel; - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MemberReferenceMethod method && handle.Equals(method.handle); } @@ -441,11 +443,11 @@ namespace Semmle.Extraction.CIL.Entities return handle.GetHashCode(); } - public override Method SourceDeclaration => sourceDeclaration; + public override Method? SourceDeclaration => sourceDeclaration; public override bool IsStatic => !signature.Header.IsInstance; - public override Type DeclaringType => declType; + public override Type DeclaringType => declaringType; public override string Name => cx.ShortName(mr.Name); @@ -465,7 +467,7 @@ namespace Semmle.Extraction.CIL.Entities var typeSignature = mr.DecodeMethodSignature(cx.TypeSignatureDecoder, this); PopulateParameters(typeSignature.ParameterTypes); - foreach (var p in Parameters) yield return p; + foreach (var p in Parameters!) yield return p; foreach (var f in PopulateFlags) yield return f; @@ -486,6 +488,7 @@ namespace Semmle.Extraction.CIL.Entities readonly MethodSpecification ms; readonly Method unboundMethod; readonly ImmutableArray typeParams; + readonly Type declaringType; public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc) { @@ -501,7 +504,7 @@ namespace Semmle.Extraction.CIL.Entities unboundMethod.WriteId(trapFile); trapFile.Write('<'); int index = 0; - foreach(var param in typeParams) + foreach (var param in typeParams) { trapFile.WriteSeparator(",", ref index); trapFile.WriteSubId(param); @@ -511,7 +514,7 @@ namespace Semmle.Extraction.CIL.Entities public override string NameLabel => throw new NotImplementedException(); - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams); } @@ -548,7 +551,7 @@ namespace Semmle.Extraction.CIL.Entities } PopulateParameters(constructedTypeSignature.ParameterTypes); - foreach (var p in Parameters) + foreach (var p in Parameters!) yield return p; foreach (var f in PopulateFlags) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs index 6a7943c8bd1..421318a757c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs @@ -17,7 +17,7 @@ namespace Semmle.Extraction.CIL.Entities /// public sealed class Namespace : TypeContainer, INamespace { - public Namespace ParentNamespace; + public Namespace? ParentNamespace; public readonly string Name; public bool IsGlobalNamespace => ParentNamespace == null; @@ -35,7 +35,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(Name); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (obj is Namespace ns && Name == ns.Name) { @@ -63,7 +63,7 @@ namespace Semmle.Extraction.CIL.Entities return i == -1 ? fqn : fqn.Substring(i + 1); } - static Namespace createParentNamespace(Context cx, string fqn) + static Namespace? createParentNamespace(Context cx, string fqn) { if (fqn == "") return null; var i = fqn.LastIndexOf('.'); @@ -74,7 +74,7 @@ namespace Semmle.Extraction.CIL.Entities { } - public Namespace(Context cx, string name, Namespace parent) : base(cx) + public Namespace(Context cx, string name, Namespace? parent) : base(cx) { Name = name; ParentNamespace = parent; @@ -86,7 +86,7 @@ namespace Semmle.Extraction.CIL.Entities { yield return Tuples.namespaces(this, Name); if (!IsGlobalNamespace) - yield return Tuples.parent_namespace(this, ParentNamespace); + yield return Tuples.parent_namespace(this, ParentNamespace!); } } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs index f48a88bcf82..38b1b735f0a 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Parameter.cs @@ -33,7 +33,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(index); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Parameter param && method.Equals(param.method) && index == param.index; } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs index 4149baf5e42..1b9c438a17d 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Property.cs @@ -48,7 +48,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(")"); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is Property property && Equals(handle, property.handle); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs index ade644fbb1c..551f2a12bdc 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/SourceLocation.cs @@ -32,7 +32,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(location.EndColumn); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PdbSourceLocation l && location.Equals(l.location); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index 04b25553b6b..3e2f9e23641 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -8,6 +8,7 @@ using System.Reflection; using Semmle.Util; using System.IO; using System.Text; +using System.Diagnostics.CodeAnalysis; namespace Semmle.Extraction.CIL.Entities { @@ -103,7 +104,7 @@ namespace Semmle.Extraction.CIL.Entities /// shortcut to comparing the signature bytes since handles are unique. /// /// The method, or 'null' if not found or not supported. - internal virtual Method LookupMethod(StringHandle methodName, BlobHandle signature) + internal virtual Method? LookupMethod(StringHandle methodName, BlobHandle signature) { return null; } @@ -160,7 +161,7 @@ namespace Semmle.Extraction.CIL.Entities get; } - public virtual TypeContainer Parent => (TypeContainer)ContainingType ?? Namespace; + public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? Namespace!; public override IEnumerable Contents { @@ -177,9 +178,9 @@ namespace Semmle.Extraction.CIL.Entities public abstract string Name { get; } - public abstract Namespace Namespace { get; } + public abstract Namespace? Namespace { get; } - public abstract Type ContainingType { get; } + public abstract Type? ContainingType { get; } public abstract Type Construct(IEnumerable typeArguments); @@ -233,7 +234,7 @@ namespace Semmle.Extraction.CIL.Entities /// /// The resulting primitive type, or null. /// True if this type is a primitive type. - public bool TryGetPrimitiveType(out PrimitiveType t) + public bool TryGetPrimitiveType([NotNullWhen(true)] out PrimitiveType? t) { if (TryGetPrimitiveTypeCode(out var code)) { @@ -249,7 +250,7 @@ namespace Semmle.Extraction.CIL.Entities private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code) { - if (ContainingType == null && Namespace.Name == cx.SystemNamespace.Name) + if (ContainingType == null && Namespace?.Name == cx.SystemNamespace.Name) { switch (Name) { @@ -341,7 +342,7 @@ namespace Semmle.Extraction.CIL.Entities typeParams = new Lazy>(MakeTypeParameters); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is TypeDefinitionType t && handle.Equals(t.handle); } @@ -390,9 +391,9 @@ namespace Semmle.Extraction.CIL.Entities public override Namespace Namespace => cx.Create(td.NamespaceDefinition); - readonly Type declType; + readonly Type? declType; - public override Type ContainingType => declType; + public override Type? ContainingType => declType; public override int ThisTypeParameters { @@ -562,18 +563,14 @@ namespace Semmle.Extraction.CIL.Entities readonly TypeReference tr; readonly Lazy typeParams; - public TypeReferenceType(Context cx, TypeReferenceHandle handle) : this(cx, handle, cx.mdReader.GetTypeReference(handle)) - { - typeParams = new Lazy(MakeTypeParameters); - } - - public TypeReferenceType(Context cx, TypeReferenceHandle handle, TypeReference tr) : base(cx) + public TypeReferenceType(Context cx, TypeReferenceHandle handle) : base(cx) { + this.typeParams = new Lazy(MakeTypeParameters); this.handle = handle; - this.tr = tr; + this.tr = cx.mdReader.GetTypeReference(handle); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is TypeReferenceType t && handle.Equals(t.handle); } @@ -637,7 +634,7 @@ namespace Semmle.Extraction.CIL.Entities } } - public override Type ContainingType + public override Type? ContainingType { get { @@ -654,7 +651,7 @@ namespace Semmle.Extraction.CIL.Entities switch (tr.ResolutionScope.Kind) { case HandleKind.TypeReference: - ContainingType.WriteAssemblyPrefix(trapFile); + ContainingType!.WriteAssemblyPrefix(trapFile); break; case HandleKind.AssemblyReference: var assemblyDef = cx.mdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope); @@ -684,7 +681,7 @@ namespace Semmle.Extraction.CIL.Entities var ct = ContainingType; if (ct != null) { - ContainingType.GetId(trapFile, inContext); + ct.GetId(trapFile, inContext); } else { @@ -719,9 +716,11 @@ namespace Semmle.Extraction.CIL.Entities public sealed class ConstructedType : Type { readonly Type unboundGenericType; - readonly Type[] thisTypeArguments; - public override IEnumerable ThisTypeArguments => thisTypeArguments; + // Either null or notEmpty + readonly Type[]? thisTypeArguments; + + public override IEnumerable ThisTypeArguments => thisTypeArguments.EnumerateNull(); public override IEnumerable ThisGenericArguments => thisTypeArguments.EnumerateNull(); @@ -751,7 +750,6 @@ namespace Semmle.Extraction.CIL.Entities unboundGenericType = unboundType; var thisParams = unboundType.ThisTypeParameters; - var parentParams = suppliedArgs - thisParams; if (typeArguments.Count() == thisParams) { @@ -760,18 +758,21 @@ namespace Semmle.Extraction.CIL.Entities } else if (thisParams == 0) { - containingType = unboundType.ContainingType.Construct(typeArguments); + // all type arguments belong to containing type + containingType = unboundType.ContainingType!.Construct(typeArguments); } else { - containingType = unboundType.ContainingType.Construct(typeArguments.Take(parentParams)); + // some type arguments belong to containing type + var parentParams = suppliedArgs - thisParams; + containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams)); thisTypeArguments = typeArguments.Skip(parentParams).ToArray(); } } - public override bool Equals(object obj) + public override bool Equals(object? obj) { - if(obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType)) + if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType)) { if (thisTypeArguments is null) return t.thisTypeArguments is null; if (!(t.thisTypeArguments is null)) return thisTypeArguments.SequenceEqual(t.thisTypeArguments); @@ -788,12 +789,12 @@ namespace Semmle.Extraction.CIL.Entities return h; } - readonly Type containingType; - public override Type ContainingType => containingType; + readonly Type? containingType; + public override Type? ContainingType => containingType; public override string Name => unboundGenericType.Name; - public override Namespace Namespace => unboundGenericType.Namespace; + public override Namespace Namespace => unboundGenericType.Namespace!; public override int ThisTypeParameters => thisTypeArguments == null ? 0 : thisTypeArguments.Length; @@ -851,7 +852,7 @@ namespace Semmle.Extraction.CIL.Entities typeCode = tc; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PrimitiveType pt && typeCode == pt.typeCode; } @@ -871,7 +872,7 @@ namespace Semmle.Extraction.CIL.Entities public override Namespace Namespace => cx.SystemNamespace; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => 0; @@ -894,19 +895,17 @@ namespace Semmle.Extraction.CIL.Entities readonly Type elementType; readonly int rank; - public ArrayType(Context cx, Type element, ArrayShape shape) : base(cx) + public ArrayType(Context cx, Type elementType, int rank) : base(cx) { - rank = shape.Rank; - elementType = element; + this.rank = rank; + this.elementType = elementType; } - public ArrayType(Context cx, Type element) : base(cx) + public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1) { - rank = 1; - elementType = element; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank; } @@ -929,7 +928,7 @@ namespace Semmle.Extraction.CIL.Entities public override Namespace Namespace => cx.SystemNamespace; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => elementType.ThisTypeParameters; @@ -972,9 +971,9 @@ namespace Semmle.Extraction.CIL.Entities this.gc = gc; } - public override Namespace Namespace => null; + public override Namespace? Namespace => null; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => 0; @@ -1034,7 +1033,7 @@ namespace Semmle.Extraction.CIL.Entities this.index = index; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index; } @@ -1072,7 +1071,7 @@ namespace Semmle.Extraction.CIL.Entities type = t; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is TypeTypeParameter tp && type.Equals(tp.type) && index == tp.index; } @@ -1089,7 +1088,7 @@ namespace Semmle.Extraction.CIL.Entities trapFile.Write(index); } - public override TypeContainer Parent => type ?? gc as TypeContainer; + public override TypeContainer Parent => type; public override string Name => "!" + index; public override IEnumerable TypeParameters => Enumerable.Empty(); @@ -1119,7 +1118,7 @@ namespace Semmle.Extraction.CIL.Entities this.pointee = pointee; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { return obj is PointerType pt && pointee.Equals(pt.pointee); } @@ -1138,9 +1137,9 @@ namespace Semmle.Extraction.CIL.Entities public override string Name => pointee.Name + "*"; - public override Namespace Namespace => pointee.Namespace; + public override Namespace? Namespace => pointee.Namespace; - public override Type ContainingType => pointee.ContainingType; + public override Type? ContainingType => pointee.ContainingType; public override TypeContainer Parent => pointee.Parent; @@ -1180,7 +1179,7 @@ namespace Semmle.Extraction.CIL.Entities public override Namespace Namespace => cx.GlobalNamespace; - public override Type ContainingType => null; + public override Type? ContainingType => null; public override int ThisTypeParameters => 0; @@ -1202,13 +1201,20 @@ namespace Semmle.Extraction.CIL.Entities { struct Array : ITypeSignature { - public ITypeSignature elementType; - public ArrayShape shape; + private readonly ITypeSignature elementType; + private readonly ArrayShape shape; + + public Array(ITypeSignature elementType, ArrayShape shape) : this() + { + this.elementType = elementType; + this.shape = shape; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { elementType.WriteId(trapFile, gc); trapFile.Write('['); - for (int i=1; i signature; + private readonly MethodSignature signature; + + public FnPtr(MethodSignature signature) + { + this.signature = signature; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1236,25 +1252,32 @@ namespace Semmle.Extraction.CIL.Entities } ITypeSignature IConstructedTypeProvider.GetArrayType(ITypeSignature elementType, ArrayShape shape) => - new Array { elementType = elementType, shape = shape }; + new Array(elementType, shape); ITypeSignature IConstructedTypeProvider.GetByReferenceType(ITypeSignature elementType) => - new ByRef { elementType = elementType }; + new ByRef(elementType); ITypeSignature ISignatureTypeProvider.GetFunctionPointerType(MethodSignature signature) => - new FnPtr { signature = signature }; + new FnPtr(signature); class Instantiation : ITypeSignature { - public ITypeSignature genericType; - public ImmutableArray typeArguments; + private readonly ITypeSignature genericType; + private readonly ImmutableArray typeArguments; + + public Instantiation(ITypeSignature genericType, ImmutableArray typeArguments) + { + this.genericType = genericType; + this.typeArguments = typeArguments; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { genericType.WriteId(trapFile, gc); trapFile.Write('<'); int index = 0; - foreach(var arg in typeArguments) + foreach (var arg in typeArguments) { trapFile.WriteSeparator(",", ref index); arg.WriteId(trapFile, gc); @@ -1264,12 +1287,18 @@ namespace Semmle.Extraction.CIL.Entities } ITypeSignature IConstructedTypeProvider.GetGenericInstantiation(ITypeSignature genericType, ImmutableArray typeArguments) => - new Instantiation { genericType = genericType, typeArguments = typeArguments }; + new Instantiation(genericType, typeArguments); class GenericMethodParameter : ITypeSignature { - public object innerGc; - public int index; + private readonly object innerGc; + private readonly int index; + + public GenericMethodParameter(object innerGc, int index) + { + this.innerGc = innerGc; + this.index = index; + } public void WriteId(TextWriter trapFile, GenericContext outerGc) { @@ -1284,7 +1313,12 @@ namespace Semmle.Extraction.CIL.Entities class GenericTypeParameter : ITypeSignature { - public int index; + private readonly int index; + + public GenericTypeParameter(int index) + { + this.index = index; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1294,16 +1328,23 @@ namespace Semmle.Extraction.CIL.Entities } ITypeSignature ISignatureTypeProvider.GetGenericMethodParameter(object genericContext, int index) => - new GenericMethodParameter { innerGc = genericContext, index = index }; + new GenericMethodParameter(genericContext, index); ITypeSignature ISignatureTypeProvider.GetGenericTypeParameter(object genericContext, int index) => - new GenericTypeParameter { index = index }; + new GenericTypeParameter(index); class Modified : ITypeSignature { - public ITypeSignature modifier; - public ITypeSignature unmodifiedType; - public bool isRequired; + private readonly ITypeSignature modifier; + private readonly ITypeSignature unmodifiedType; + private readonly bool isRequired; + + public Modified(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired) + { + this.modifier = modifier; + this.unmodifiedType = unmodifiedType; + this.isRequired = isRequired; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1313,12 +1354,17 @@ namespace Semmle.Extraction.CIL.Entities ITypeSignature ISignatureTypeProvider.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired) { - return new Modified { modifier = modifier, unmodifiedType = unmodifiedType, isRequired = isRequired }; + return new Modified(modifier, unmodifiedType, isRequired); } class Pinned : ITypeSignature { - public ITypeSignature elementType; + private readonly ITypeSignature elementType; + + public Pinned(ITypeSignature elementType) + { + this.elementType = elementType; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1329,12 +1375,17 @@ namespace Semmle.Extraction.CIL.Entities ITypeSignature ISignatureTypeProvider.GetPinnedType(ITypeSignature elementType) { - return new Pinned { elementType = elementType }; + return new Pinned(elementType); } class PointerType : ITypeSignature { - public ITypeSignature elementType; + private readonly ITypeSignature elementType; + + public PointerType(ITypeSignature elementType) + { + this.elementType = elementType; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1345,12 +1396,17 @@ namespace Semmle.Extraction.CIL.Entities ITypeSignature IConstructedTypeProvider.GetPointerType(ITypeSignature elementType) { - return new PointerType { elementType = elementType }; + return new PointerType(elementType); } class Primitive : ITypeSignature { - public PrimitiveTypeCode typeCode; + private readonly PrimitiveTypeCode typeCode; + + public Primitive(PrimitiveTypeCode typeCode) + { + this.typeCode = typeCode; + } public void WriteId(TextWriter trapFile, GenericContext gc) { @@ -1360,12 +1416,18 @@ namespace Semmle.Extraction.CIL.Entities ITypeSignature ISimpleTypeProvider.GetPrimitiveType(PrimitiveTypeCode typeCode) { - return new Primitive { typeCode = typeCode }; + return new Primitive(typeCode); } class SzArrayType : ITypeSignature { - public ITypeSignature elementType; + private readonly ITypeSignature elementType; + + public SzArrayType(ITypeSignature elementType) + { + this.elementType = elementType; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { elementType.WriteId(trapFile, gc); @@ -1375,41 +1437,53 @@ namespace Semmle.Extraction.CIL.Entities ITypeSignature ISZArrayTypeProvider.GetSZArrayType(ITypeSignature elementType) { - return new SzArrayType { elementType = elementType }; + return new SzArrayType(elementType); } class TypeDefinition : ITypeSignature { - public TypeDefinitionHandle handle; - public byte rawTypeKind; - Type type; + private readonly TypeDefinitionHandle handle; + private readonly byte rawTypeKind; + + public TypeDefinition(TypeDefinitionHandle handle, byte rawTypeKind) + { + this.handle = handle; + this.rawTypeKind = rawTypeKind; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { - type = (Type)gc.cx.Create(handle); + var type = (Type)gc.cx.Create(handle); type.WriteId(trapFile); } } ITypeSignature ISimpleTypeProvider.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) { - return new TypeDefinition { handle = handle, rawTypeKind = rawTypeKind }; + return new TypeDefinition(handle, rawTypeKind); } class TypeReference : ITypeSignature { - public TypeReferenceHandle handle; - public byte rawTypeKind; // struct/class (not used) - Type type; + private readonly TypeReferenceHandle handle; + private readonly byte rawTypeKind; // struct/class (not used) + + public TypeReference(TypeReferenceHandle handle, byte rawTypeKind) + { + this.handle = handle; + this.rawTypeKind = rawTypeKind; + } + public void WriteId(TextWriter trapFile, GenericContext gc) { - type = (Type)gc.cx.Create(handle); + var type = (Type)gc.cx.Create(handle); type.WriteId(trapFile); } } ITypeSignature ISimpleTypeProvider.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) { - return new TypeReference { handle = handle, rawTypeKind = rawTypeKind }; + return new TypeReference(handle, rawTypeKind); } ITypeSignature ISignatureTypeProvider.GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind) @@ -1433,7 +1507,7 @@ namespace Semmle.Extraction.CIL.Entities } Type IConstructedTypeProvider.GetArrayType(Type elementType, ArrayShape shape) => - cx.Populate(new ArrayType(cx, elementType, shape)); + cx.Populate(new ArrayType(cx, elementType, shape.Rank)); Type IConstructedTypeProvider.GetByReferenceType(Type elementType) => elementType; // ?? diff --git a/csharp/extractor/Semmle.Extraction.CIL/Factories.cs b/csharp/extractor/Semmle.Extraction.CIL/Factories.cs index f522521a845..f2f98b64d17 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Factories.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Factories.cs @@ -41,7 +41,7 @@ namespace Semmle.Extraction.CIL e.WriteId(writer); var id = writer.ToString(); - if (debugLabels.TryGetValue(id, out IExtractedEntity previousEntity)) + if (debugLabels.TryGetValue(id, out IExtractedEntity? previousEntity)) { cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning)); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs index 33e8460090d..14bd9fdeb72 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/MetadataPdbReader.cs @@ -25,7 +25,7 @@ namespace Semmle.Extraction.PDB public string Path { get; private set; } - public string Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null; + public string? Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null; } // Turns out to be very important to keep the MetadataReaderProvider live @@ -41,7 +41,7 @@ namespace Semmle.Extraction.PDB public IEnumerable SourceFiles => reader.Documents.Select(handle => new SourceFile(reader, handle)); - public IMethod GetMethod(MethodDebugInformationHandle handle) + public IMethod? GetMethod(MethodDebugInformationHandle handle) { var debugInfo = reader.GetMethodDebugInformation(handle); @@ -51,10 +51,10 @@ namespace Semmle.Extraction.PDB Where(p => p.Location.File.Path != null). ToArray(); - return sequencePoints.Any() ? new Method() { SequencePoints = sequencePoints } : null; + return sequencePoints.Any() ? new Method(sequencePoints) : null; } - public static MetadataPdbReader CreateFromAssembly(string assemblyPath, PEReader peReader) + public static MetadataPdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader) { foreach (var provider in peReader. ReadDebugDirectory(). diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs index 0f25b281aab..283fd4bf35b 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/NativePdbReader.cs @@ -23,7 +23,7 @@ namespace Semmle.Extraction.PDB public Document(ISymUnmanagedDocument doc) { document = doc; - contents = new Lazy(() => + contents = new Lazy(() => { bool isEmbedded; if (document.HasEmbeddedSource(out isEmbedded) == 0 && isEmbedded) @@ -38,7 +38,7 @@ namespace Semmle.Extraction.PDB }); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var otherDoc = obj as Document; return otherDoc != null && Path.Equals(otherDoc.Path); @@ -50,14 +50,14 @@ namespace Semmle.Extraction.PDB public override string ToString() => Path; - readonly Lazy contents; + readonly Lazy contents; - public string Contents => contents.Value; + public string? Contents => contents.Value; } public IEnumerable SourceFiles => reader.GetDocuments().Select(d => new Document(d)); - public IMethod GetMethod(MethodDebugInformationHandle h) + public IMethod? GetMethod(MethodDebugInformationHandle h) { int methodToken = MetadataTokens.GetToken(h.ToDefinitionHandle()); var method = reader.GetMethod(methodToken); @@ -72,7 +72,7 @@ namespace Semmle.Extraction.PDB Select(sp => new SequencePoint(sp.Offset, new Location(new Document(sp.Document), sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn))). ToArray(); - return s.Any() ? new Method { SequencePoints = s } : null; + return s.Any() ? new Method(s) : null; } return null; } @@ -87,7 +87,7 @@ namespace Semmle.Extraction.PDB readonly ISymUnmanagedReader5 reader; readonly FileStream pdbStream; - public static NativePdbReader CreateFromAssembly(string assemblyPath, PEReader peReader) + public static NativePdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader) { // The Native PDB reader uses an unmanaged Windows DLL // so only works on Windows. @@ -123,7 +123,7 @@ namespace Semmle.Extraction.PDB { } - public object GetMetadataImport() => null; + public object? GetMetadataImport() => null; public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length) => throw new NotImplementedException(); diff --git a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs index c2f4f94f59f..8fb83554649 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/PDB/PdbReader.cs @@ -55,7 +55,7 @@ namespace Semmle.Extraction.PDB return string.Format("({0},{1})-({2},{3})", StartLine, StartColumn, EndLine, EndColumn); } - public override bool Equals(object obj) + public override bool Equals(object? obj) { var otherLocation = obj as Location; @@ -91,7 +91,12 @@ namespace Semmle.Extraction.PDB class Method : IMethod { - public IEnumerable SequencePoints { get; set; } + public IEnumerable SequencePoints { get; } + + public Method(IEnumerable sequencePoints) + { + SequencePoints = sequencePoints; + } public Location Location => SequencePoints.First().Location; } @@ -111,7 +116,7 @@ namespace Semmle.Extraction.PDB /// null if the contents are unavailable. /// E.g. if the PDB file exists but the corresponding source files are missing. /// - string Contents { get; } + string? Contents { get; } } /// @@ -131,7 +136,7 @@ namespace Semmle.Extraction.PDB /// /// The handle to query. /// The method information, or null if the method does not have debug information. - IMethod GetMethod(MethodDebugInformationHandle methodHandle); + IMethod? GetMethod(MethodDebugInformationHandle methodHandle); } class PdbReader @@ -140,11 +145,11 @@ namespace Semmle.Extraction.PDB /// Returns the PDB information associated with an assembly. /// /// The path to the assembly. - /// The PE reader for the assembky. + /// The PE reader for the assembly. /// A PdbReader, or null if no PDB information is available. - public static IPdb Create(string assemblyPath, PEReader peReader) + public static IPdb? Create(string assemblyPath, PEReader peReader) { - return (IPdb)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ?? + return (IPdb?)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ?? NativePdbReader.CreateFromAssembly(assemblyPath, peReader); } } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj index 9db880787b0..6626eda5474 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj @@ -7,6 +7,7 @@ false true win-x64;linux-x64;osx-x64 + enable diff --git a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs index 7665dedfa70..d8d3f8cb581 100644 --- a/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs +++ b/csharp/extractor/Semmle.Util/IEnumerableExtensions.cs @@ -64,7 +64,7 @@ namespace Semmle.Util /// Enumerates a possibly null enumerable. /// If the enumerable is null, the list is empty. /// - public static IEnumerable EnumerateNull(this IEnumerable items) + public static IEnumerable EnumerateNull(this IEnumerable? items) { if (items == null) yield break; foreach (var item in items) yield return item; @@ -93,7 +93,7 @@ namespace Semmle.Util /// The type of the item. /// The list of items to hash. /// The hash code. - public static int SequenceHash(this IEnumerable items) where T: notnull + public static int SequenceHash(this IEnumerable items) where T : notnull { int h = 0; foreach (var i in items) From 8e2b2540facb9f0d03c51b8f7a00391336ec5081 Mon Sep 17 00:00:00 2001 From: yoff Date: Fri, 21 Aug 2020 09:39:00 +0200 Subject: [PATCH 082/146] Apply suggestions from code review Co-authored-by: Rasmus Wriedt Larsen --- .../src/experimental/dataflow/internal/DataFlowPublic.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 55fe94350cc..cfb1d81a829 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -56,7 +56,7 @@ class Node extends TNode { EssaVariable asVar() { none() } /** Convenience method for casting to CfgNode and calling getNode. */ - DataFlowCfgNode asCfgNode() { none() } + ControlFlowNode asCfgNode() { none() } /** Convenience method for casting to ExprNode and calling getNode and getNode again. */ Expr asExpr() { none() } @@ -84,9 +84,9 @@ class CfgNode extends Node, TCfgNode { CfgNode() { this = TCfgNode(node) } - DataFlowCfgNode getNode() { result = node } + ControlFlowNode getNode() { result = node } - override DataFlowCfgNode asCfgNode() { result = node } + override ControlFlowNode asCfgNode() { result = node } /** Gets a textual representation of this element. */ override string toString() { result = node.toString() } From e00951edf078d8d99752f14722e2d9ce8994867e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 21 Aug 2020 09:50:27 +0200 Subject: [PATCH 083/146] update TypeScript to 4.0.2 --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index e66383a5ef3..0fa2d78d7d5 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "4.0.1-rc" + "typescript": "4.0.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index 0fcb30d02f2..42c9f33d41c 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -225,9 +225,9 @@ tsutils@^2.12.1: dependencies: tslib "^1.8.1" -typescript@4.0.1-rc: - version "4.0.1-rc" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.1-rc.tgz#8adc78223eae56fe71d906a5fa90c3543b07a677" +typescript@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" wrappy@1: version "1.0.2" From 07610e0899bcd5902658073b3b39f381a0e66541 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Mon, 24 Aug 2020 13:12:54 +0200 Subject: [PATCH 084/146] Format document --- .../Likely Bugs/RedundantNullCheckParam.ql | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql index d09191a3891..c67e15aceba 100644 --- a/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql +++ b/cpp/ql/src/experimental/Likely Bugs/RedundantNullCheckParam.ql @@ -19,10 +19,7 @@ predicate blockDominates(Block check, Block access) { } predicate isCheckedInstruction(VariableAccess unchecked, VariableAccess checked) { - checked = - any(VariableAccess va | - va.getTarget() = unchecked.getTarget() - ) and + checked = any(VariableAccess va | va.getTarget() = unchecked.getTarget()) and //Simple test if the first access in this code path is dereferenced not dereferenced(checked) and blockDominates(checked.getEnclosingBlock(), unchecked.getEnclosingBlock()) @@ -38,7 +35,8 @@ predicate candidateResultChecked(VariableAccess check, EqualityOperation eqop) { //assert macros are not taken into account not check.isInMacroExpansion() and // is part of a comparison against some constant NULL - eqop.getAnOperand() = check and eqop.getAnOperand() instanceof NullValue + eqop.getAnOperand() = check and + eqop.getAnOperand() instanceof NullValue } from VariableAccess unchecked, VariableAccess check, EqualityOperation eqop, Parameter param @@ -54,4 +52,5 @@ where candidateResultChecked(check, eqop) and // and which has not been checked before in this code path candidateResultUnchecked(unchecked) -select check, "This null check is redundant or there is a missing null check before $@ ", unchecked, "where dereferencing happens" +select check, "This null check is redundant or there is a missing null check before $@ ", unchecked, + "where dereferencing happens" From 699cafa890d5d269649e1f559d1f9a67840ed6ec Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 24 Aug 2020 15:27:35 +0200 Subject: [PATCH 085/146] C#: Add implicitly sized array creations to tests --- .../expressions/AnonymousMethod1.expected | 2 +- .../expressions/AnonymousMethod2.expected | 2 +- .../expressions/AnonymousMethod3.expected | 2 +- .../expressions/AnonymousMethod4.expected | 2 +- .../expressions/AnonymousMethod5.expected | 2 +- .../expressions/ArrayCreation11.expected | 28 + .../expressions/Lambda1.expected | 2 +- .../expressions/Lambda2.expected | 2 +- .../expressions/Lambda3.expected | 2 +- .../expressions/Lambda4.expected | 2 +- .../expressions/Lambda5.expected | 2 +- .../expressions/Lambda6.expected | 2 +- .../expressions/OperatorCall6.expected | 8 +- .../expressions/OperatorCall7.expected | 4 +- .../expressions/PrintAst.expected | 755 ++++++++++-------- .../expressions/QualifiableExpr.expected | 8 +- .../expressions/StripCasts.expected | 8 +- .../expressions/Tuples1.expected | 8 +- .../library-tests/expressions/expressions.cs | 12 + 19 files changed, 507 insertions(+), 346 deletions(-) diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected index 99cbc7b7280..a443b2e5f58 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod1.expected @@ -1 +1 @@ -| expressions.cs:443:33:443:66 | delegate(...) { ... } | +| expressions.cs:455:33:455:66 | delegate(...) { ... } | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected index 71d45f3859b..a4eb1c44ada 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod2.expected @@ -1 +1 @@ -| expressions.cs:443:33:443:66 | delegate(...) { ... } | expressions.cs:443:47:443:47 | x | +| expressions.cs:455:33:455:66 | delegate(...) { ... } | expressions.cs:455:47:455:47 | x | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected index 99cbc7b7280..a443b2e5f58 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod3.expected @@ -1 +1 @@ -| expressions.cs:443:33:443:66 | delegate(...) { ... } | +| expressions.cs:455:33:455:66 | delegate(...) { ... } | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected index f1ea5fb3021..650c309ba90 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod4.expected @@ -1 +1 @@ -| expressions.cs:445:28:445:53 | delegate(...) { ... } | expressions.cs:445:28:445:53 | delegate(...) { ... } | +| expressions.cs:457:28:457:53 | delegate(...) { ... } | expressions.cs:457:28:457:53 | delegate(...) { ... } | diff --git a/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected b/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected index aa2ee29ffda..2f79004d8ef 100644 --- a/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected +++ b/csharp/ql/test/library-tests/expressions/AnonymousMethod5.expected @@ -1 +1 @@ -| expressions.cs:445:28:445:53 | delegate(...) { ... } | expressions.cs:445:46:445:46 | access to local variable j | +| expressions.cs:457:28:457:53 | delegate(...) { ... } | expressions.cs:457:46:457:46 | access to local variable j | diff --git a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected index f0e5752ac75..80714fe6906 100644 --- a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected +++ b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected @@ -1,3 +1,31 @@ | expressions.cs:168:27:168:44 | array creation of type Object[] | expressions.cs:168:27:168:44 | 1 | true | | expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true | | expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true | +| expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 3 | true | +| expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 3 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:441:19:441:45 | array creation of type Int32[,] | expressions.cs:441:19:441:45 | 2 | true | +| expressions.cs:441:19:441:45 | array creation of type Int32[,] | expressions.cs:441:19:441:45 | 2 | true | +| expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 3 | true | +| expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 3 | true | +| expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 3 | true | +| expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 3 | true | +| expressions.cs:442:19:442:45 | array creation of type Int32[,] | expressions.cs:442:19:442:45 | 2 | true | +| expressions.cs:442:19:442:45 | array creation of type Int32[,] | expressions.cs:442:19:442:45 | 2 | true | +| expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 3 | true | +| expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 3 | true | +| expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 3 | true | +| expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 3 | true | +| expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | +| expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | +| expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | +| expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 1 | true | +| expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 1 | true | +| expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 1 | true | +| expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 1 | true | diff --git a/csharp/ql/test/library-tests/expressions/Lambda1.expected b/csharp/ql/test/library-tests/expressions/Lambda1.expected index 030ff70fac4..34e99d531ad 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda1.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda1.expected @@ -1 +1 @@ -| expressions.cs:437:36:437:53 | (...) => ... | +| expressions.cs:449:36:449:53 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda2.expected b/csharp/ql/test/library-tests/expressions/Lambda2.expected index 6b9ab4d13af..a59313cf13e 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda2.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda2.expected @@ -1 +1 @@ -| expressions.cs:438:38:438:59 | (...) => ... | +| expressions.cs:450:38:450:59 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda3.expected b/csharp/ql/test/library-tests/expressions/Lambda3.expected index 0a17c1914d6..f00475e2298 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda3.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda3.expected @@ -1 +1 @@ -| expressions.cs:439:33:439:48 | (...) => ... | +| expressions.cs:451:33:451:48 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda4.expected b/csharp/ql/test/library-tests/expressions/Lambda4.expected index da7c72353ae..92b0dea6fa5 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda4.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda4.expected @@ -1 +1 @@ -| expressions.cs:440:36:440:64 | (...) => ... | +| expressions.cs:452:36:452:64 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda5.expected b/csharp/ql/test/library-tests/expressions/Lambda5.expected index cc846823df4..08d4b5546ae 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda5.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda5.expected @@ -1 +1 @@ -| expressions.cs:441:20:441:34 | (...) => ... | +| expressions.cs:453:20:453:34 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/Lambda6.expected b/csharp/ql/test/library-tests/expressions/Lambda6.expected index 83d1caa259d..55427d92103 100644 --- a/csharp/ql/test/library-tests/expressions/Lambda6.expected +++ b/csharp/ql/test/library-tests/expressions/Lambda6.expected @@ -1 +1 @@ -| expressions.cs:442:23:442:47 | (...) => ... | +| expressions.cs:454:23:454:47 | (...) => ... | diff --git a/csharp/ql/test/library-tests/expressions/OperatorCall6.expected b/csharp/ql/test/library-tests/expressions/OperatorCall6.expected index 208e70975f3..4f483ef92e2 100644 --- a/csharp/ql/test/library-tests/expressions/OperatorCall6.expected +++ b/csharp/ql/test/library-tests/expressions/OperatorCall6.expected @@ -1,4 +1,4 @@ -| expressions.cs:458:20:458:27 | addition | expressions.cs:460:26:460:26 | access to parameter a | expressions.cs:473:40:473:40 | + | -| expressions.cs:458:20:458:27 | addition | expressions.cs:460:30:460:30 | access to parameter b | expressions.cs:473:40:473:40 | + | -| expressions.cs:458:20:458:27 | addition | expressions.cs:461:13:461:18 | access to local variable result | expressions.cs:473:40:473:40 | + | -| expressions.cs:458:20:458:27 | addition | expressions.cs:461:23:461:23 | access to parameter c | expressions.cs:473:40:473:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:472:26:472:26 | access to parameter a | expressions.cs:485:40:485:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:472:30:472:30 | access to parameter b | expressions.cs:485:40:485:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:473:13:473:18 | access to local variable result | expressions.cs:485:40:485:40 | + | +| expressions.cs:470:20:470:27 | addition | expressions.cs:473:23:473:23 | access to parameter c | expressions.cs:485:40:485:40 | + | diff --git a/csharp/ql/test/library-tests/expressions/OperatorCall7.expected b/csharp/ql/test/library-tests/expressions/OperatorCall7.expected index b59bcd180fa..46f56cef5ac 100644 --- a/csharp/ql/test/library-tests/expressions/OperatorCall7.expected +++ b/csharp/ql/test/library-tests/expressions/OperatorCall7.expected @@ -1,2 +1,2 @@ -| expressions.cs:452:21:452:35 | delegateCombine | expressions.cs:450:11:450:23 | OperatorCalls | expressions.cs:455:13:455:27 | access to local variable PropertyChanged | expressions.cs:479:30:479:39 | MyDelegate | -| expressions.cs:452:21:452:35 | delegateCombine | expressions.cs:450:11:450:23 | OperatorCalls | expressions.cs:455:32:455:34 | access to parameter fun | expressions.cs:479:30:479:39 | MyDelegate | +| expressions.cs:464:21:464:35 | delegateCombine | expressions.cs:462:11:462:23 | OperatorCalls | expressions.cs:467:13:467:27 | access to local variable PropertyChanged | expressions.cs:491:30:491:39 | MyDelegate | +| expressions.cs:464:21:464:35 | delegateCombine | expressions.cs:462:11:462:23 | OperatorCalls | expressions.cs:467:32:467:34 | access to parameter fun | expressions.cs:491:30:491:39 | MyDelegate | diff --git a/csharp/ql/test/library-tests/expressions/PrintAst.expected b/csharp/ql/test/library-tests/expressions/PrintAst.expected index 0e10aa2711e..fff855518da 100644 --- a/csharp/ql/test/library-tests/expressions/PrintAst.expected +++ b/csharp/ql/test/library-tests/expressions/PrintAst.expected @@ -1491,333 +1491,454 @@ expressions.cs: # 432| 0: [Parameter] x # 432| 1: [Parameter] y # 433| 7: [DelegateType] Unit -# 435| 8: [Method] MainAnonymousFunctions +# 435| 8: [Method] MultiDimensionalArrayCreations # 436| 4: [BlockStmt] {...} # 437| 0: [LocalVariableDeclStmt] ... ...; -# 437| 0: [LocalVariableDeclAndInitExpr] Func f1 = ... -# 437| 0: [LambdaExpr] (...) => ... -# 437| 0: [CastExpr] (...) ... -# 437| 0: [AddExpr] ... + ... -# 437| 0: [CastExpr] (...) ... -# 437| 0: [ParameterAccess] access to parameter x -# 437| 1: [IntLiteral] 1 -# 437| 1: [TypeAccess] access to type Byte +# 437| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 437| 0: [ArrayCreation] array creation of type Int32[,] +# 437| -1: [ArrayInitializer] { ..., ... } +# 437| 0: [ArrayInitializer] { ..., ... } +# 437| 0: [IntLiteral] 1 +# 437| 1: [IntLiteral] 2 +# 437| 1: [ArrayInitializer] { ..., ... } +# 437| 0: [IntLiteral] 3 +# 437| 1: [IntLiteral] 4 +# 437| 2: [ArrayInitializer] { ..., ... } +# 437| 0: [IntLiteral] 5 +# 437| 1: [IntLiteral] 6 +# 437| 1: [LocalVariableAccess] access to local variable o +# 438| 1: [ExprStmt] ...; +# 438| 0: [AssignExpr] ... = ... +# 438| 0: [ArrayCreation] array creation of type Int32[,,] +# 438| -1: [ArrayInitializer] { ..., ... } +# 438| 0: [ArrayInitializer] { ..., ... } +# 438| 0: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 1 +# 438| 1: [IntLiteral] 2 +# 438| 2: [IntLiteral] 3 +# 438| 1: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 4 +# 438| 1: [IntLiteral] 5 +# 438| 2: [IntLiteral] 6 +# 438| 1: [ArrayInitializer] { ..., ... } +# 438| 0: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 7 +# 438| 1: [IntLiteral] 8 +# 438| 2: [IntLiteral] 9 +# 438| 1: [ArrayInitializer] { ..., ... } +# 438| 0: [IntLiteral] 10 +# 438| 1: [IntLiteral] 11 +# 438| 2: [IntLiteral] 12 +# 438| 1: [LocalVariableAccess] access to local variable o +# 439| 2: [ExprStmt] ...; +# 439| 0: [AssignExpr] ... = ... +# 439| 0: [ArrayCreation] array creation of type Int32[,][,] +# 440| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayCreation] array creation of type Int32[,] +# 441| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 1 +# 441| 1: [IntLiteral] 3 +# 441| 1: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 5 +# 441| 1: [IntLiteral] 7 +# 441| 1: [ArrayCreation] array creation of type Int32[,] +# 441| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 0 +# 441| 1: [IntLiteral] 2 +# 441| 1: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 4 +# 441| 1: [IntLiteral] 6 +# 441| 2: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 8 +# 441| 1: [IntLiteral] 10 +# 441| 2: [ArrayCreation] array creation of type Int32[,] +# 441| -1: [ArrayInitializer] { ..., ... } +# 441| 0: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 11 +# 441| 1: [IntLiteral] 22 +# 441| 1: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 99 +# 441| 1: [IntLiteral] 88 +# 441| 2: [ArrayInitializer] { ..., ... } +# 441| 0: [IntLiteral] 0 +# 441| 1: [IntLiteral] 9 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayCreation] array creation of type Int32[,] +# 442| -1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 1 +# 442| 1: [IntLiteral] 3 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 5 +# 442| 1: [IntLiteral] 7 +# 442| 1: [ArrayCreation] array creation of type Int32[,] +# 442| -1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 0 +# 442| 1: [IntLiteral] 2 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 4 +# 442| 1: [IntLiteral] 6 +# 442| 2: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 8 +# 442| 1: [IntLiteral] 10 +# 442| 2: [ArrayCreation] array creation of type Int32[,] +# 442| -1: [ArrayInitializer] { ..., ... } +# 442| 0: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 11 +# 442| 1: [IntLiteral] 22 +# 442| 1: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 99 +# 442| 1: [IntLiteral] 88 +# 442| 2: [ArrayInitializer] { ..., ... } +# 442| 0: [IntLiteral] 0 +# 442| 1: [IntLiteral] 9 +# 439| 1: [LocalVariableAccess] access to local variable o +# 444| 3: [ExprStmt] ...; +# 444| 0: [AssignExpr] ... = ... +# 444| 0: [ArrayCreation] array creation of type Int32[,][] +# 444| -1: [ArrayInitializer] { ..., ... } +# 444| 0: [ArrayCreation] array creation of type Int32[,] +# 444| -1: [ArrayInitializer] { ..., ... } +# 444| 0: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 1: [ArrayCreation] array creation of type Int32[,] +# 444| -1: [ArrayInitializer] { ..., ... } +# 444| 0: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 1: [LocalVariableAccess] access to local variable o +# 447| 9: [Method] MainAnonymousFunctions +# 448| 4: [BlockStmt] {...} +# 449| 0: [LocalVariableDeclStmt] ... ...; +# 449| 0: [LocalVariableDeclAndInitExpr] Func f1 = ... +# 449| 0: [LambdaExpr] (...) => ... +# 449| 0: [CastExpr] (...) ... +# 449| 0: [AddExpr] ... + ... +# 449| 0: [CastExpr] (...) ... +# 449| 0: [ParameterAccess] access to parameter x +# 449| 1: [IntLiteral] 1 +# 449| 1: [TypeAccess] access to type Byte #-----| 2: (Parameters) -# 437| 0: [Parameter] x -# 437| 1: [LocalVariableAccess] access to local variable f1 -# 438| 1: [LocalVariableDeclStmt] ... ...; -# 438| 0: [LocalVariableDeclAndInitExpr] Func f2 = ... -# 438| 0: [LambdaExpr] (...) => ... -# 438| 0: [BlockStmt] {...} -# 438| 0: [ReturnStmt] return ...; -# 438| 0: [CastExpr] (...) ... -# 438| 0: [AddExpr] ... + ... -# 438| 0: [ParameterAccess] access to parameter x -# 438| 1: [IntLiteral] 1 +# 449| 0: [Parameter] x +# 449| 1: [LocalVariableAccess] access to local variable f1 +# 450| 1: [LocalVariableDeclStmt] ... ...; +# 450| 0: [LocalVariableDeclAndInitExpr] Func f2 = ... +# 450| 0: [LambdaExpr] (...) => ... +# 450| 0: [BlockStmt] {...} +# 450| 0: [ReturnStmt] return ...; +# 450| 0: [CastExpr] (...) ... +# 450| 0: [AddExpr] ... + ... +# 450| 0: [ParameterAccess] access to parameter x +# 450| 1: [IntLiteral] 1 #-----| 2: (Parameters) -# 438| 0: [Parameter] x -# 438| 1: [LocalVariableAccess] access to local variable f2 -# 439| 2: [LocalVariableDeclStmt] ... ...; -# 439| 0: [LocalVariableDeclAndInitExpr] Func f3 = ... -# 439| 0: [LambdaExpr] (...) => ... -# 439| 0: [AddExpr] ... + ... -# 439| 0: [ParameterAccess] access to parameter x -# 439| 1: [IntLiteral] 1 +# 450| 0: [Parameter] x +# 450| 1: [LocalVariableAccess] access to local variable f2 +# 451| 2: [LocalVariableDeclStmt] ... ...; +# 451| 0: [LocalVariableDeclAndInitExpr] Func f3 = ... +# 451| 0: [LambdaExpr] (...) => ... +# 451| 0: [AddExpr] ... + ... +# 451| 0: [ParameterAccess] access to parameter x +# 451| 1: [IntLiteral] 1 #-----| 2: (Parameters) -# 439| 0: [Parameter] x -# 439| 1: [LocalVariableAccess] access to local variable f3 -# 440| 3: [LocalVariableDeclStmt] ... ...; -# 440| 0: [LocalVariableDeclAndInitExpr] Func f4 = ... -# 440| 0: [LambdaExpr] (...) => ... -# 440| 0: [BlockStmt] {...} -# 440| 0: [ReturnStmt] return ...; -# 440| 0: [AddExpr] ... + ... -# 440| 0: [CastExpr] (...) ... -# 440| 0: [ParameterAccess] access to parameter x -# 440| 1: [StringLiteral] "" +# 451| 0: [Parameter] x +# 451| 1: [LocalVariableAccess] access to local variable f3 +# 452| 3: [LocalVariableDeclStmt] ... ...; +# 452| 0: [LocalVariableDeclAndInitExpr] Func f4 = ... +# 452| 0: [LambdaExpr] (...) => ... +# 452| 0: [BlockStmt] {...} +# 452| 0: [ReturnStmt] return ...; +# 452| 0: [AddExpr] ... + ... +# 452| 0: [CastExpr] (...) ... +# 452| 0: [ParameterAccess] access to parameter x +# 452| 1: [StringLiteral] "" #-----| 2: (Parameters) -# 440| 0: [Parameter] x -# 440| 1: [LocalVariableAccess] access to local variable f4 -# 441| 4: [LocalVariableDeclStmt] ... ...; -# 441| 0: [LocalVariableDeclAndInitExpr] S f5 = ... -# 441| 0: [LambdaExpr] (...) => ... -# 441| 0: [MulExpr] ... * ... -# 441| 0: [ParameterAccess] access to parameter x -# 441| 1: [ParameterAccess] access to parameter y +# 452| 0: [Parameter] x +# 452| 1: [LocalVariableAccess] access to local variable f4 +# 453| 4: [LocalVariableDeclStmt] ... ...; +# 453| 0: [LocalVariableDeclAndInitExpr] S f5 = ... +# 453| 0: [LambdaExpr] (...) => ... +# 453| 0: [MulExpr] ... * ... +# 453| 0: [ParameterAccess] access to parameter x +# 453| 1: [ParameterAccess] access to parameter y #-----| 2: (Parameters) -# 441| 0: [Parameter] x -# 441| 1: [Parameter] y -# 441| 1: [LocalVariableAccess] access to local variable f5 -# 442| 5: [LocalVariableDeclStmt] ... ...; -# 442| 0: [LocalVariableDeclAndInitExpr] Unit f6 = ... -# 442| 0: [LambdaExpr] (...) => ... -# 442| 0: [MethodCall] call to method WriteLine -# 442| -1: [TypeAccess] access to type Console -# 442| 1: [LocalVariableAccess] access to local variable f6 -# 443| 6: [LocalVariableDeclStmt] ... ...; -# 443| 0: [LocalVariableDeclAndInitExpr] Func f7 = ... -# 443| 0: [AnonymousMethodExpr] delegate(...) { ... } -# 443| 0: [BlockStmt] {...} -# 443| 0: [ReturnStmt] return ...; -# 443| 0: [AddExpr] ... + ... -# 443| 0: [ParameterAccess] access to parameter x -# 443| 1: [IntLiteral] 1 +# 453| 0: [Parameter] x +# 453| 1: [Parameter] y +# 453| 1: [LocalVariableAccess] access to local variable f5 +# 454| 5: [LocalVariableDeclStmt] ... ...; +# 454| 0: [LocalVariableDeclAndInitExpr] Unit f6 = ... +# 454| 0: [LambdaExpr] (...) => ... +# 454| 0: [MethodCall] call to method WriteLine +# 454| -1: [TypeAccess] access to type Console +# 454| 1: [LocalVariableAccess] access to local variable f6 +# 455| 6: [LocalVariableDeclStmt] ... ...; +# 455| 0: [LocalVariableDeclAndInitExpr] Func f7 = ... +# 455| 0: [AnonymousMethodExpr] delegate(...) { ... } +# 455| 0: [BlockStmt] {...} +# 455| 0: [ReturnStmt] return ...; +# 455| 0: [AddExpr] ... + ... +# 455| 0: [ParameterAccess] access to parameter x +# 455| 1: [IntLiteral] 1 #-----| 2: (Parameters) -# 443| 0: [Parameter] x -# 443| 1: [LocalVariableAccess] access to local variable f7 -# 444| 7: [LocalVariableDeclStmt] ... ...; -# 444| 0: [LocalVariableDeclAndInitExpr] Int32 j = ... -# 444| 0: [IntLiteral] 0 -# 444| 1: [LocalVariableAccess] access to local variable j -# 445| 8: [LocalVariableDeclStmt] ... ...; -# 445| 0: [LocalVariableDeclAndInitExpr] Func f8 = ... -# 445| 0: [AnonymousMethodExpr] delegate(...) { ... } -# 445| 0: [BlockStmt] {...} -# 445| 0: [ReturnStmt] return ...; -# 445| 0: [AddExpr] ... + ... -# 445| 0: [LocalVariableAccess] access to local variable j -# 445| 1: [IntLiteral] 1 -# 445| 1: [LocalVariableAccess] access to local variable f8 -# 450| 18: [Class] OperatorCalls -# 452| 5: [Method] delegateCombine +# 455| 0: [Parameter] x +# 455| 1: [LocalVariableAccess] access to local variable f7 +# 456| 7: [LocalVariableDeclStmt] ... ...; +# 456| 0: [LocalVariableDeclAndInitExpr] Int32 j = ... +# 456| 0: [IntLiteral] 0 +# 456| 1: [LocalVariableAccess] access to local variable j +# 457| 8: [LocalVariableDeclStmt] ... ...; +# 457| 0: [LocalVariableDeclAndInitExpr] Func f8 = ... +# 457| 0: [AnonymousMethodExpr] delegate(...) { ... } +# 457| 0: [BlockStmt] {...} +# 457| 0: [ReturnStmt] return ...; +# 457| 0: [AddExpr] ... + ... +# 457| 0: [LocalVariableAccess] access to local variable j +# 457| 1: [IntLiteral] 1 +# 457| 1: [LocalVariableAccess] access to local variable f8 +# 462| 18: [Class] OperatorCalls +# 464| 5: [Method] delegateCombine #-----| 2: (Parameters) -# 452| 0: [Parameter] fun -# 453| 4: [BlockStmt] {...} -# 454| 0: [LocalVariableDeclStmt] ... ...; -# 454| 0: [LocalVariableDeclAndInitExpr] MyDelegate PropertyChanged = ... -# 454| 0: [NullLiteral] null -# 454| 1: [LocalVariableAccess] access to local variable PropertyChanged -# 455| 1: [ExprStmt] ...; -# 455| 0: [AssignAddExpr] ... += ... -# 455| 0: [ParameterAccess] access to parameter fun -# 455| 1: [LocalVariableAccess] access to local variable PropertyChanged -# 458| 6: [Method] addition +# 464| 0: [Parameter] fun +# 465| 4: [BlockStmt] {...} +# 466| 0: [LocalVariableDeclStmt] ... ...; +# 466| 0: [LocalVariableDeclAndInitExpr] MyDelegate PropertyChanged = ... +# 466| 0: [NullLiteral] null +# 466| 1: [LocalVariableAccess] access to local variable PropertyChanged +# 467| 1: [ExprStmt] ...; +# 467| 0: [AssignAddExpr] ... += ... +# 467| 0: [ParameterAccess] access to parameter fun +# 467| 1: [LocalVariableAccess] access to local variable PropertyChanged +# 470| 6: [Method] addition #-----| 2: (Parameters) -# 458| 0: [Parameter] a -# 458| 1: [Parameter] b -# 458| 2: [Parameter] c -# 459| 4: [BlockStmt] {...} -# 460| 0: [LocalVariableDeclStmt] ... ...; -# 460| 0: [LocalVariableDeclAndInitExpr] Num result = ... -# 460| 0: [OperatorCall] call to operator + -# 460| 0: [ParameterAccess] access to parameter a -# 460| 1: [ParameterAccess] access to parameter b -# 460| 1: [LocalVariableAccess] access to local variable result -# 461| 1: [ExprStmt] ...; -# 461| 0: [AssignAddExpr] ... += ... -# 461| 0: [ParameterAccess] access to parameter c -# 461| 1: [LocalVariableAccess] access to local variable result -# 462| 2: [ReturnStmt] return ...; -# 462| 0: [LocalVariableAccess] access to local variable result -# 464| 7: [Class] Num -# 466| 4: [Field] value -# 468| 5: [InstanceConstructor] Num +# 470| 0: [Parameter] a +# 470| 1: [Parameter] b +# 470| 2: [Parameter] c +# 471| 4: [BlockStmt] {...} +# 472| 0: [LocalVariableDeclStmt] ... ...; +# 472| 0: [LocalVariableDeclAndInitExpr] Num result = ... +# 472| 0: [OperatorCall] call to operator + +# 472| 0: [ParameterAccess] access to parameter a +# 472| 1: [ParameterAccess] access to parameter b +# 472| 1: [LocalVariableAccess] access to local variable result +# 473| 1: [ExprStmt] ...; +# 473| 0: [AssignAddExpr] ... += ... +# 473| 0: [ParameterAccess] access to parameter c +# 473| 1: [LocalVariableAccess] access to local variable result +# 474| 2: [ReturnStmt] return ...; +# 474| 0: [LocalVariableAccess] access to local variable result +# 476| 7: [Class] Num +# 478| 4: [Field] value +# 480| 5: [InstanceConstructor] Num #-----| 2: (Parameters) -# 468| 0: [Parameter] value -# 469| 4: [BlockStmt] {...} -# 470| 0: [ExprStmt] ...; -# 470| 0: [AssignExpr] ... = ... -# 470| 0: [ParameterAccess] access to parameter value -# 470| 1: [FieldAccess] access to field value -# 470| -1: [ThisAccess] this access -# 473| 6: [AddOperator] + +# 480| 0: [Parameter] value +# 481| 4: [BlockStmt] {...} +# 482| 0: [ExprStmt] ...; +# 482| 0: [AssignExpr] ... = ... +# 482| 0: [ParameterAccess] access to parameter value +# 482| 1: [FieldAccess] access to field value +# 482| -1: [ThisAccess] this access +# 485| 6: [AddOperator] + #-----| 2: (Parameters) -# 473| 0: [Parameter] c1 -# 473| 1: [Parameter] c2 -# 474| 4: [BlockStmt] {...} -# 475| 0: [ReturnStmt] return ...; -# 475| 0: [ObjectCreation] object creation of type Num -# 475| 0: [AddExpr] ... + ... -# 475| 0: [FieldAccess] access to field value -# 475| -1: [ParameterAccess] access to parameter c1 -# 475| 1: [FieldAccess] access to field value -# 475| -1: [ParameterAccess] access to parameter c2 -# 479| 8: [DelegateType] MyDelegate +# 485| 0: [Parameter] c1 +# 485| 1: [Parameter] c2 +# 486| 4: [BlockStmt] {...} +# 487| 0: [ReturnStmt] return ...; +# 487| 0: [ObjectCreation] object creation of type Num +# 487| 0: [AddExpr] ... + ... +# 487| 0: [FieldAccess] access to field value +# 487| -1: [ParameterAccess] access to parameter c1 +# 487| 1: [FieldAccess] access to field value +# 487| -1: [ParameterAccess] access to parameter c2 +# 491| 8: [DelegateType] MyDelegate #-----| 2: (Parameters) -# 479| 0: [Parameter] e -# 482| 19: [Class] ExpressionDepth -# 484| 5: [Field] d -# 484| 1: [AssignExpr] ... = ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [AddExpr] ... + ... -# 484| 0: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 484| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 485| 1: [IntLiteral] 1 -# 484| 1: [MemberConstantAccess] access to constant d -# 488| 20: [Class] TupleExprs -# 490| 5: [Method] Test -# 491| 4: [BlockStmt] {...} -# 492| 0: [LocalVariableDeclStmt] ... ...; -# 492| 0: [LocalVariableDeclAndInitExpr] (Int32,String) a = ... -# 492| 0: [DefaultValueExpr] default(...) -# 492| 0: [TypeAccess] access to type (Int32,String) -# 492| 1: [LocalVariableAccess] access to local variable a -# 493| 1: [LocalVariableDeclStmt] ... ...; -# 493| 0: [LocalVariableDeclAndInitExpr] (Boolean,Int32[],Object) b = ... -# 493| 0: [DefaultValueExpr] default(...) -# 493| 0: [TypeAccess] access to type (Boolean,Int32[],Object) -# 493| 1: [LocalVariableAccess] access to local variable b -# 494| 2: [LocalVariableDeclStmt] ... ...; -# 494| 0: [LocalVariableDeclAndInitExpr] Type x = ... -# 494| 0: [TypeofExpr] typeof(...) -# 494| 0: [TypeAccess] access to type (Int32,String) -# 494| 1: [LocalVariableAccess] access to local variable x -# 495| 3: [LocalVariableDeclStmt] ... ...; -# 495| 0: [LocalVariableDeclAndInitExpr] Type y = ... -# 495| 0: [TypeofExpr] typeof(...) -# 495| 0: [TypeAccess] access to type (Boolean,Int32[],dynamic) -# 495| 1: [LocalVariableAccess] access to local variable y +# 491| 0: [Parameter] e +# 494| 19: [Class] ExpressionDepth +# 496| 5: [Field] d +# 496| 1: [AssignExpr] ... = ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [AddExpr] ... + ... +# 496| 0: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 496| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 497| 1: [IntLiteral] 1 +# 496| 1: [MemberConstantAccess] access to constant d +# 500| 20: [Class] TupleExprs +# 502| 5: [Method] Test +# 503| 4: [BlockStmt] {...} +# 504| 0: [LocalVariableDeclStmt] ... ...; +# 504| 0: [LocalVariableDeclAndInitExpr] (Int32,String) a = ... +# 504| 0: [DefaultValueExpr] default(...) +# 504| 0: [TypeAccess] access to type (Int32,String) +# 504| 1: [LocalVariableAccess] access to local variable a +# 505| 1: [LocalVariableDeclStmt] ... ...; +# 505| 0: [LocalVariableDeclAndInitExpr] (Boolean,Int32[],Object) b = ... +# 505| 0: [DefaultValueExpr] default(...) +# 505| 0: [TypeAccess] access to type (Boolean,Int32[],Object) +# 505| 1: [LocalVariableAccess] access to local variable b +# 506| 2: [LocalVariableDeclStmt] ... ...; +# 506| 0: [LocalVariableDeclAndInitExpr] Type x = ... +# 506| 0: [TypeofExpr] typeof(...) +# 506| 0: [TypeAccess] access to type (Int32,String) +# 506| 1: [LocalVariableAccess] access to local variable x +# 507| 3: [LocalVariableDeclStmt] ... ...; +# 507| 0: [LocalVariableDeclAndInitExpr] Type y = ... +# 507| 0: [TypeofExpr] typeof(...) +# 507| 0: [TypeAccess] access to type (Boolean,Int32[],dynamic) +# 507| 1: [LocalVariableAccess] access to local variable y diff --git a/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected b/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected index 0013cee52a9..f5b5c0aa892 100644 --- a/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected +++ b/csharp/ql/test/library-tests/expressions/QualifiableExpr.expected @@ -65,7 +65,7 @@ | expressions.cs:377:43:377:46 | access to field name | expressions.cs:377:43:377:46 | this access | | expressions.cs:377:57:377:60 | access to field name | expressions.cs:377:57:377:60 | this access | | expressions.cs:378:57:378:68 | access to field phoneNumbers | expressions.cs:378:57:378:68 | this access | -| expressions.cs:442:29:442:47 | call to method WriteLine | expressions.cs:442:29:442:35 | access to type Console | -| expressions.cs:470:17:470:26 | access to field value | expressions.cs:470:17:470:20 | this access | -| expressions.cs:475:32:475:39 | access to field value | expressions.cs:475:32:475:33 | access to parameter c1 | -| expressions.cs:475:43:475:50 | access to field value | expressions.cs:475:43:475:44 | access to parameter c2 | +| expressions.cs:454:29:454:47 | call to method WriteLine | expressions.cs:454:29:454:35 | access to type Console | +| expressions.cs:482:17:482:26 | access to field value | expressions.cs:482:17:482:20 | this access | +| expressions.cs:487:32:487:39 | access to field value | expressions.cs:487:32:487:33 | access to parameter c1 | +| expressions.cs:487:43:487:50 | access to field value | expressions.cs:487:43:487:44 | access to parameter c2 | diff --git a/csharp/ql/test/library-tests/expressions/StripCasts.expected b/csharp/ql/test/library-tests/expressions/StripCasts.expected index bf16559809a..6fdfa4be3d5 100644 --- a/csharp/ql/test/library-tests/expressions/StripCasts.expected +++ b/csharp/ql/test/library-tests/expressions/StripCasts.expected @@ -50,7 +50,7 @@ | expressions.cs:334:30:334:30 | (...) ... | expressions.cs:334:30:334:30 | 8 | | expressions.cs:414:31:414:31 | (...) ... | expressions.cs:414:31:414:31 | 1 | | expressions.cs:414:39:414:39 | (...) ... | expressions.cs:414:39:414:39 | 2 | -| expressions.cs:437:41:437:53 | (...) ... | expressions.cs:437:48:437:52 | ... + ... | -| expressions.cs:437:48:437:48 | (...) ... | expressions.cs:437:48:437:48 | access to parameter x | -| expressions.cs:438:52:438:56 | (...) ... | expressions.cs:438:52:438:56 | ... + ... | -| expressions.cs:440:56:440:56 | (...) ... | expressions.cs:440:56:440:56 | access to parameter x | +| expressions.cs:449:41:449:53 | (...) ... | expressions.cs:449:48:449:52 | ... + ... | +| expressions.cs:449:48:449:48 | (...) ... | expressions.cs:449:48:449:48 | access to parameter x | +| expressions.cs:450:52:450:56 | (...) ... | expressions.cs:450:52:450:56 | ... + ... | +| expressions.cs:452:56:452:56 | (...) ... | expressions.cs:452:56:452:56 | access to parameter x | diff --git a/csharp/ql/test/library-tests/expressions/Tuples1.expected b/csharp/ql/test/library-tests/expressions/Tuples1.expected index 70210471b03..ea05f07d8eb 100644 --- a/csharp/ql/test/library-tests/expressions/Tuples1.expected +++ b/csharp/ql/test/library-tests/expressions/Tuples1.expected @@ -1,4 +1,4 @@ -| expressions.cs:492:29:492:41 | access to type (Int32,String) | expressions.cs:492:29:492:41 | (Int32,String) | -| expressions.cs:493:29:493:49 | access to type (Boolean,Int32[],Object) | expressions.cs:493:29:493:49 | (Boolean,Int32[],Object) | -| expressions.cs:494:28:494:40 | access to type (Int32,String) | expressions.cs:492:29:492:41 | (Int32,String) | -| expressions.cs:495:28:495:49 | access to type (Boolean,Int32[],dynamic) | expressions.cs:495:28:495:49 | (Boolean,Int32[],dynamic) | +| expressions.cs:504:29:504:41 | access to type (Int32,String) | expressions.cs:504:29:504:41 | (Int32,String) | +| expressions.cs:505:29:505:49 | access to type (Boolean,Int32[],Object) | expressions.cs:505:29:505:49 | (Boolean,Int32[],Object) | +| expressions.cs:506:28:506:40 | access to type (Int32,String) | expressions.cs:504:29:504:41 | (Int32,String) | +| expressions.cs:507:28:507:49 | access to type (Boolean,Int32[],dynamic) | expressions.cs:507:28:507:49 | (Boolean,Int32[],dynamic) | diff --git a/csharp/ql/test/library-tests/expressions/expressions.cs b/csharp/ql/test/library-tests/expressions/expressions.cs index aea2d80729c..c9e7419af9b 100644 --- a/csharp/ql/test/library-tests/expressions/expressions.cs +++ b/csharp/ql/test/library-tests/expressions/expressions.cs @@ -432,6 +432,18 @@ namespace Expressions delegate int S(int x, int y); delegate void Unit(); + void MultiDimensionalArrayCreations() + { + object o = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 } }; + o = new int[,,] { { { 1, 2, 3 }, { 4, 5, 6 } }, { { 7, 8, 9 }, { 10, 11, 12 } } }; + o = new int[,][,] + { + { new int[,] { {1,3}, {5,7} }, new int[,] { {0,2}, {4,6}, {8,10} }, new int[,] { {11,22}, {99,88}, {0,9} } }, + { new int[,] { {1,3}, {5,7} }, new int[,] { {0,2}, {4,6}, {8,10} }, new int[,] { {11,22}, {99,88}, {0,9} } } + }; + o = new int[][,] { new int[,] { { 1, 2 } }, new int[,] { { 1, 2 } } }; + } + void MainAnonymousFunctions() { Func f1 = x => (byte)(x + 1); // Implicitly typed, expression body From 7516825b5faa3cc24df18f2b559aec583bd42510 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 24 Aug 2020 16:08:13 +0200 Subject: [PATCH 086/146] C#: Fix computed sizes for implicitly sized array creation --- .../Entities/Expressions/ArrayCreation.cs | 71 +++++++++++-------- .../expressions/ArrayCreation11.expected | 24 +++---- 2 files changed, 50 insertions(+), 45 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs index 068cf2368fd..6c31ba9ac35 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ArrayCreation.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Semmle.Extraction.Kinds; using System.IO; @@ -21,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions protected override void PopulateExpression(TextWriter trapFile) { - var child = 0; + var explicitlySized = false; if (TypeSyntax is null) @@ -29,38 +30,21 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions cx.ModelError(Syntax, "Array has unexpected type syntax"); } - foreach (var rank in TypeSyntax.RankSpecifiers.SelectMany(rs => rs.Sizes)) + var firstLevelSizes = TypeSyntax.RankSpecifiers.First()?.Sizes ?? SyntaxFactory.SeparatedList(); + + if (firstLevelSizes.OfType().Any(s => s is OmittedArraySizeExpressionSyntax)) { - if (rank is OmittedArraySizeExpressionSyntax) - { - // Create an expression which simulates the explicit size of the array - - if (!(Initializer is null)) - { - // An implicitly-sized array must have an initializer. - // Guard it just in case. - var size = Initializer.Expressions.Count; - - var info = new ExpressionInfo( - cx, - new AnnotatedType(Entities.Type.Create(cx, cx.Compilation.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32)), NullableAnnotation.None), - Location, - ExprKind.INT_LITERAL, - this, - child, - true, - size.ToString()); - - new Expression(info); - } - } - else - { - Create(cx, rank, this, child); - explicitlySized = true; - } - child++; + SetArraySizes(Initializer, firstLevelSizes.Count); } + else + { + for (var sizeIndex = 0; sizeIndex < firstLevelSizes.Count; sizeIndex++) + { + Create(cx, firstLevelSizes[sizeIndex], this, sizeIndex); + } + explicitlySized = true; + } + if (!(Initializer is null)) { ArrayInitializer.Create(new ExpressionNodeInfo(cx, Initializer, this, -1)); @@ -69,6 +53,31 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions if (explicitlySized) trapFile.explicitly_sized_array_creation(this); } + + private void SetArraySizes(InitializerExpressionSyntax initializer, int rank) + { + for (var level = 0; level < rank; level++) + { + if (initializer is null) + { + return; + } + + var info = new ExpressionInfo( + cx, + new AnnotatedType(Entities.Type.Create(cx, cx.Compilation.GetSpecialType(Microsoft.CodeAnalysis.SpecialType.System_Int32)), NullableAnnotation.None), + Location, + ExprKind.INT_LITERAL, + this, + level, + true, + initializer.Expressions.Count.ToString()); + + new Expression(info); + + initializer = initializer.Expressions.FirstOrDefault() as InitializerExpressionSyntax; + } + } } class NormalArrayCreation : ExplicitArrayCreation diff --git a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected index 80714fe6906..9542bb21b21 100644 --- a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected +++ b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected @@ -1,31 +1,27 @@ | expressions.cs:168:27:168:44 | array creation of type Object[] | expressions.cs:168:27:168:44 | 1 | true | +| expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 2 | true | | expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true | -| expressions.cs:409:23:409:65 | array creation of type Int32[,] | expressions.cs:409:23:409:65 | 3 | true | -| expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 3 | true | +| expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 2 | true | | expressions.cs:437:24:437:66 | array creation of type Int32[,] | expressions.cs:437:24:437:66 | 3 | true | | expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | | expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | -| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 2 | true | -| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | -| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | -| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:438:17:438:93 | array creation of type Int32[,,] | expressions.cs:438:17:438:93 | 3 | true | | expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 2 | true | +| expressions.cs:439:17:443:13 | array creation of type Int32[,][,] | expressions.cs:439:17:443:13 | 3 | true | | expressions.cs:441:19:441:45 | array creation of type Int32[,] | expressions.cs:441:19:441:45 | 2 | true | | expressions.cs:441:19:441:45 | array creation of type Int32[,] | expressions.cs:441:19:441:45 | 2 | true | +| expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 2 | true | | expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 3 | true | -| expressions.cs:441:48:441:82 | array creation of type Int32[,] | expressions.cs:441:48:441:82 | 3 | true | -| expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 3 | true | +| expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 2 | true | | expressions.cs:441:85:441:122 | array creation of type Int32[,] | expressions.cs:441:85:441:122 | 3 | true | | expressions.cs:442:19:442:45 | array creation of type Int32[,] | expressions.cs:442:19:442:45 | 2 | true | | expressions.cs:442:19:442:45 | array creation of type Int32[,] | expressions.cs:442:19:442:45 | 2 | true | +| expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 2 | true | | expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 3 | true | -| expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 3 | true | -| expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 3 | true | +| expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 2 | true | | expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 3 | true | | expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | -| expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | -| expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | -| expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 1 | true | | expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 1 | true | +| expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 2 | true | | expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 1 | true | -| expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 1 | true | +| expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 2 | true | From 3dea6b32182c0dce8a7c91d0df7be3ff3b3e40e9 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 24 Aug 2020 16:10:42 +0200 Subject: [PATCH 087/146] C#: Change implicitly sized array test input --- .../test/library-tests/expressions/ArrayCreation11.expected | 6 +++--- csharp/ql/test/library-tests/expressions/expressions.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected index 9542bb21b21..2fa6120d695 100644 --- a/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected +++ b/csharp/ql/test/library-tests/expressions/ArrayCreation11.expected @@ -20,8 +20,8 @@ | expressions.cs:442:48:442:82 | array creation of type Int32[,] | expressions.cs:442:48:442:82 | 3 | true | | expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 2 | true | | expressions.cs:442:85:442:122 | array creation of type Int32[,] | expressions.cs:442:85:442:122 | 3 | true | -| expressions.cs:444:17:444:81 | array creation of type Int32[,][] | expressions.cs:444:17:444:81 | 2 | true | +| expressions.cs:444:17:444:123 | array creation of type Int32[,][] | expressions.cs:444:17:444:123 | 2 | true | | expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 1 | true | | expressions.cs:444:32:444:54 | array creation of type Int32[,] | expressions.cs:444:32:444:54 | 2 | true | -| expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 1 | true | -| expressions.cs:444:57:444:79 | array creation of type Int32[,] | expressions.cs:444:57:444:79 | 2 | true | +| expressions.cs:444:57:444:121 | array creation of type Int32[,] | expressions.cs:444:57:444:121 | 3 | true | +| expressions.cs:444:57:444:121 | array creation of type Int32[,] | expressions.cs:444:57:444:121 | 4 | true | diff --git a/csharp/ql/test/library-tests/expressions/expressions.cs b/csharp/ql/test/library-tests/expressions/expressions.cs index c9e7419af9b..5d995e10985 100644 --- a/csharp/ql/test/library-tests/expressions/expressions.cs +++ b/csharp/ql/test/library-tests/expressions/expressions.cs @@ -441,7 +441,7 @@ namespace Expressions { new int[,] { {1,3}, {5,7} }, new int[,] { {0,2}, {4,6}, {8,10} }, new int[,] { {11,22}, {99,88}, {0,9} } }, { new int[,] { {1,3}, {5,7} }, new int[,] { {0,2}, {4,6}, {8,10} }, new int[,] { {11,22}, {99,88}, {0,9} } } }; - o = new int[][,] { new int[,] { { 1, 2 } }, new int[,] { { 1, 2 } } }; + o = new int[][,] { new int[,] { { 1, 2 } }, new int[,] { { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } } }; } void MainAnonymousFunctions() From 22f5ae4ad432f7a4ad60181ccdeddf145e667d92 Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Mon, 24 Aug 2020 18:53:37 +0200 Subject: [PATCH 088/146] Format code --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index d08548df993..d735399bfb0 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -16,4 +16,4 @@ import InsecureCookie::Cookie from Cookie cookie where not cookie.isSecure() select "Cookie is added to response without the 'secure' flag being set to true (using " + -cookie.getKind() + ").", cookie + cookie.getKind() + ").", cookie From 66e3739e726033c02a034c3c99bde1d7fee87b88 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 24 Aug 2020 22:41:08 +0200 Subject: [PATCH 089/146] Fix failing PrintAst test --- .../library-tests/expressions/PrintAst.expected | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/csharp/ql/test/library-tests/expressions/PrintAst.expected b/csharp/ql/test/library-tests/expressions/PrintAst.expected index fff855518da..d12b1451a41 100644 --- a/csharp/ql/test/library-tests/expressions/PrintAst.expected +++ b/csharp/ql/test/library-tests/expressions/PrintAst.expected @@ -1611,6 +1611,19 @@ expressions.cs: # 444| 0: [ArrayInitializer] { ..., ... } # 444| 0: [IntLiteral] 1 # 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 1: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 2: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 +# 444| 3: [ArrayInitializer] { ..., ... } +# 444| 0: [IntLiteral] 1 +# 444| 1: [IntLiteral] 2 +# 444| 2: [IntLiteral] 3 # 444| 1: [LocalVariableAccess] access to local variable o # 447| 9: [Method] MainAnonymousFunctions # 448| 4: [BlockStmt] {...} From 3140b43db2862b08d1ec975e0bba6b453c0f4eab Mon Sep 17 00:00:00 2001 From: yoff Date: Tue, 25 Aug 2020 10:48:01 +0200 Subject: [PATCH 090/146] Apply suggestions from code review Co-authored-by: Taus --- python/ql/src/semmle/python/SpecialMethods.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/ql/src/semmle/python/SpecialMethods.qll b/python/ql/src/semmle/python/SpecialMethods.qll index d7fd44471f8..2218791794e 100644 --- a/python/ql/src/semmle/python/SpecialMethods.qll +++ b/python/ql/src/semmle/python/SpecialMethods.qll @@ -10,7 +10,7 @@ import python -/** A control flow node which might correpsond to a special method call. */ +/** A control flow node which might correspond to a special method call. */ class PotentialSpecialMethodCallNode extends ControlFlowNode { PotentialSpecialMethodCallNode() { this instanceof SpecialMethod::Potential } } @@ -20,12 +20,12 @@ class PotentialSpecialMethodCallNode extends ControlFlowNode { * Extend `SpecialMethod::Potential` to capture more cases. */ module SpecialMethod { - /** A control flow node which might correpsond to a special method call. */ + /** A control flow node which might correspond to a special method call. */ abstract class Potential extends ControlFlowNode { /** Gets the name of the method that would be called. */ abstract string getSpecialMethodName(); - /** Gets the controlflow node that would be passed as the specified argument. */ + /** Gets the control flow node that would be passed as the specified argument. */ abstract ControlFlowNode getArg(int n); /** From 997388b075eedc38f03abfda3f1ab99062a63742 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 25 Aug 2020 17:11:34 +0200 Subject: [PATCH 091/146] Fix first set of code review comments --- csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs | 2 +- csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs | 4 ++-- .../extractor/Semmle.Extraction.CIL/Entities/Namespace.cs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs index 0ff31dcc6f1..2506ea6ee00 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/File.cs @@ -37,7 +37,7 @@ namespace Semmle.Extraction.CIL.Entities get { var directoryName = System.IO.Path.GetDirectoryName(path); - if (directoryName == null) + if (directoryName is null) throw new InternalError($"Directory name for path '{path}' is null."); var parent = cx.CreateFolder(directoryName); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index cc9fb49afa9..ba1ede610c2 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -146,7 +146,7 @@ namespace Semmle.Extraction.CIL.Entities readonly PDB.IMethod? methodDebugInformation; readonly Type declaringType; - string name; + readonly string name; LocalVariable[]? locals; public MethodImplementation? Implementation { get; private set; } @@ -417,7 +417,7 @@ namespace Semmle.Extraction.CIL.Entities var parentMethod = parent as Method; - var declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType; + var declType = parentMethod is null ? parent as Type : parentMethod.DeclaringType; if (declType is null) throw new InternalError("Parent context of method is not a type"); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs index 421318a757c..0a808fe40e9 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Namespace.cs @@ -20,7 +20,7 @@ namespace Semmle.Extraction.CIL.Entities public Namespace? ParentNamespace; public readonly string Name; - public bool IsGlobalNamespace => ParentNamespace == null; + public bool IsGlobalNamespace => ParentNamespace is null; public override string IdSuffix => ";namespace"; @@ -85,8 +85,8 @@ namespace Semmle.Extraction.CIL.Entities get { yield return Tuples.namespaces(this, Name); - if (!IsGlobalNamespace) - yield return Tuples.parent_namespace(this, ParentNamespace!); + if (ParentNamespace is object) + yield return Tuples.parent_namespace(this, ParentNamespace); } } } From 57cf447188583ee0bb93533a5ae7d3cec2d69b4c Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed, 26 Aug 2020 01:46:59 +0200 Subject: [PATCH 092/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index e43eb61d5f7..7d097cbe267 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -77,7 +77,7 @@ module Cookie { */ class InsecureExpressCookieResponse extends Cookie { InsecureExpressCookieResponse() { - this = any(Express::ResponseExpr response).flow().getALocalSource().getAMethodCall("cookie") + this.calls(any(Express::ResponseExpr r).flow(), "cookie") } override string getKind() { result = "response.cookie" } From 3bd7615a75167fc75c899197b80ca4bc1b35ea01 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed, 26 Aug 2020 01:47:37 +0200 Subject: [PATCH 093/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 7d097cbe267..a664cf0cd94 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -75,7 +75,7 @@ module Cookie { /** * A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie). */ - class InsecureExpressCookieResponse extends Cookie { + class InsecureExpressCookieResponse extends Cookie, DataFlow::MethodCallNode { InsecureExpressCookieResponse() { this.calls(any(Express::ResponseExpr r).flow(), "cookie") } From a1f64e26cfd0056d2e35716f2cb579ec8d9171d7 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed, 26 Aug 2020 01:47:52 +0200 Subject: [PATCH 094/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index a664cf0cd94..a9b408a5303 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -83,7 +83,7 @@ module Cookie { override string getKind() { result = "response.cookie" } override DataFlow::SourceNode getCookieOptionsArgument() { - result = this.(DataFlow::InvokeNode).getLastArgument().getALocalSource() + result = this.getLastArgument().getALocalSource() } private DataFlow::Node getCookieFlagValue(string flag) { From e027c8cc1356224ebda40585eeb838e8ea182269 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed, 26 Aug 2020 01:48:05 +0200 Subject: [PATCH 095/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll Co-authored-by: Esben Sparre Andreasen --- .../src/experimental/Security/CWE-614/InsecureCookie.qll | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index a9b408a5303..05999853050 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -124,9 +124,10 @@ module Cookie { */ class InsecureJsCookie extends Cookie { InsecureJsCookie() { - this = DataFlow::globalVarRef("Cookie").getAMemberCall("set") or - this = DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict").getAMemberCall("set") or - this = DataFlow::moduleMember("js-cookie", "set").getACall() + this = + [DataFlow::globalVarRef("Cookie"), + DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"), + DataFlow::moduleImport("js-cookie")].getAMemberCall("set") } override string getKind() { result = "js-cookie" } From 36a9e4717818a65160c77ec10c02536377109c83 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 09:13:01 +0200 Subject: [PATCH 096/146] C#: Add missing QlDoc for dotnet base constructs --- csharp/ql/src/semmle/code/dotnet/Callable.qll | 5 +++++ csharp/ql/src/semmle/code/dotnet/Variable.qll | 2 ++ 2 files changed, 7 insertions(+) diff --git a/csharp/ql/src/semmle/code/dotnet/Callable.qll b/csharp/ql/src/semmle/code/dotnet/Callable.qll index 443c0040a58..8e8de83f881 100644 --- a/csharp/ql/src/semmle/code/dotnet/Callable.qll +++ b/csharp/ql/src/semmle/code/dotnet/Callable.qll @@ -1,3 +1,8 @@ +/** + * Provides `Callable` classes, which are things that can be called + * such as methods and constructors. + */ + import Declaration import Variable import Expr diff --git a/csharp/ql/src/semmle/code/dotnet/Variable.qll b/csharp/ql/src/semmle/code/dotnet/Variable.qll index 0ae3706b711..c004b9ab6b3 100644 --- a/csharp/ql/src/semmle/code/dotnet/Variable.qll +++ b/csharp/ql/src/semmle/code/dotnet/Variable.qll @@ -1,3 +1,5 @@ +/** Provides classes for .Net variables, such as fields and parameters. */ + import Declaration import Callable From 048428a6fa75f04d5d3f9506a80a137952be0e00 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 09:31:13 +0200 Subject: [PATCH 097/146] C#: Add missinq QlDoc for Serialization classes, remove unused DangerousCallable --- .../csharp/serialization/Deserializers.qll | 10 +++++++++ .../csharp/serialization/Serialization.qll | 22 ++++++++----------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll index 685a48b7079..14a7a48361c 100644 --- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll +++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll @@ -8,6 +8,9 @@ import csharp /** An unsafe deserializer. */ abstract class UnsafeDeserializer extends Callable { } +/** + * Known unsafe deserializer methods in the `System.*` namespace. + */ class SystemDeserializer extends UnsafeDeserializer { SystemDeserializer() { this @@ -48,12 +51,19 @@ class SystemDeserializer extends UnsafeDeserializer { } } +/** + * Known unsafe deserializer methods in the `Microsoft.*` namespace. + */ class MicrosoftDeserializer extends UnsafeDeserializer { MicrosoftDeserializer() { this.hasQualifiedName("Microsoft.Web.Design.Remote.ProxyObject", "DecodeValue") } } +/** + * Unsafe deserializer methods that call unsafe deserializers on the + * parameters. + */ class WrapperDeserializer extends UnsafeDeserializer { WrapperDeserializer() { exists(Call call | diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll b/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll index bf7dff102ec..047d1c411c7 100644 --- a/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll +++ b/csharp/ql/src/semmle/code/csharp/serialization/Serialization.qll @@ -1,5 +1,14 @@ +/** + * Provides classes to identify any .Net serializable type such as types + * attributed with `SerializableAttribute` and types implementing the + * `ISerializable` interface. + */ + import csharp +/** + * A constructor with `SerializationInfo` and `StreamingContext` parameters. + */ class SerializationConstructor extends Constructor { SerializationConstructor() { this.getNumberOfParameters() = 2 and @@ -91,16 +100,3 @@ class CustomBinarySerializableType extends BinarySerializableType { result.(SerializationConstructor).getDeclaringType() = this } } - -class DangerousCallable extends Callable { - DangerousCallable() { - //files - this.(Method).getQualifiedName().matches("System.IO.File.Write%") or - this.(Method).getQualifiedName().matches("System.IO.File.%Copy%") or - this.(Method).getQualifiedName().matches("System.IO.File.%Move%") or - this.(Method).getQualifiedName().matches("System.IO.File.%Append%") or - this.(Method).getQualifiedName().matches("System.IO.%.%Delete%") or - //assembly - this.(Method).getQualifiedName().matches("System.Reflection.Assembly.%Load%") - } -} From ce68e458e0ef830d7774f3d519672ad80bef960c Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 10:32:23 +0200 Subject: [PATCH 098/146] C#: Add QlDoc for predicates in Helpers --- csharp/ql/src/Linq/Helpers.qll | 44 ++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/csharp/ql/src/Linq/Helpers.qll b/csharp/ql/src/Linq/Helpers.qll index 09643be429a..fe50ca11396 100644 --- a/csharp/ql/src/Linq/Helpers.qll +++ b/csharp/ql/src/Linq/Helpers.qll @@ -6,18 +6,32 @@ import csharp //#################### PREDICATES #################### -Stmt firstStmt(ForeachStmt fes) { +private Stmt firstStmt(ForeachStmt fes) { if fes.getBody() instanceof BlockStmt then result = fes.getBody().(BlockStmt).getStmt(0) else result = fes.getBody() } +private int numStmts(ForeachStmt fes) { + if fes.getBody() instanceof BlockStmt + then result = count(fes.getBody().(BlockStmt).getAStmt()) + else result = 1 +} + +/** Holds if the type's qualified name is "System.Linq.Enumerable" */ predicate isEnumerableType(ValueOrRefType t) { t.hasQualifiedName("System.Linq.Enumerable") } +/** Holds if the type's qualified name starts with "System.Collections.Generic.IEnumerable" */ predicate isIEnumerableType(ValueOrRefType t) { t.getQualifiedName().matches("System.Collections.Generic.IEnumerable%") } +/** + * Holds if `ForeachStmt` could be converted to a `.All()` call. That is, + * the `ForeachStmt` contains a single `if` with a condition that accesses + * the loop variable and with a body that assigns `false` to a variable and + * `break`s out of the `foreach`. + */ predicate missedAllOpportunity(ForeachStmt fes) { exists(IfStmt is | // The loop contains an if statement with no else case, and nothing else. @@ -36,6 +50,11 @@ predicate missedAllOpportunity(ForeachStmt fes) { ) } +/** + * Holds if `ForeachStmt` could be converted to a `.Cast()` call. That is, the + * loop variable is accessed only in the first statement of the block, and the + * access is a cast. The first statement needs to be a `LocalVariableDeclStmt`. + */ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | @@ -47,6 +66,12 @@ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { ) } +/** + * Holds if `ForeachStmt` could be converted to an `.OfType()` call. That is, the + * loop variable is accessed only in the first statement of the block, and the + * access is a cast with the `as` operator. The first statement needs to be a + * `LocalVariableDeclStmt`. + */ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | @@ -58,6 +83,11 @@ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { ) } +/** + * Holds if `ForeachStmt` could be converted to a `.Select()` call. That is, the + * loop variable is accessed only in the first statement of the block, and the + * access is not a cast. The first statement needs to be a `LocalVariableDeclStmt`. + */ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and forex(VariableAccess va | va = fes.getVariable().getAnAccess() | @@ -66,6 +96,12 @@ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { not s.getAVariableDeclExpr().getInitializer() instanceof Cast } +/** + * Holds if `ForeachStmt` could be converted to a `.Where()` call. That is, first + * statement of the loop is an `if`, which accesses the loop variable, and the body + * of the `if` is either a `continue` or there's nothing else in the loop than the + * `if`. + */ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) { // The very first thing the foreach loop does is test its iteration variable. is = firstStmt(fes) and @@ -82,12 +118,6 @@ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) { ) } -int numStmts(ForeachStmt fes) { - if fes.getBody() instanceof BlockStmt - then result = count(fes.getBody().(BlockStmt).getAStmt()) - else result = 1 -} - //#################### CLASSES #################### /** A LINQ Any(...) call. */ class AnyCall extends MethodCall { From 4be15af06a0eafa7018ccf65086073cc57506828 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 11:18:40 +0200 Subject: [PATCH 099/146] C#: Add missing QlDoc for various predicates --- csharp/ql/src/semmle/code/cil/Access.qll | 1 + csharp/ql/src/semmle/code/csharp/Callable.qll | 3 +++ csharp/ql/src/semmle/code/csharp/Conversion.qll | 5 +++++ .../ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll | 1 + csharp/ql/src/semmle/code/csharp/exprs/Expr.qll | 1 + csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll | 4 ++++ 6 files changed, 15 insertions(+) diff --git a/csharp/ql/src/semmle/code/cil/Access.qll b/csharp/ql/src/semmle/code/cil/Access.qll index 263e527dfec..871e6f7b416 100644 --- a/csharp/ql/src/semmle/code/cil/Access.qll +++ b/csharp/ql/src/semmle/code/cil/Access.qll @@ -31,6 +31,7 @@ class ReadRefAccess extends ReadAccess, ReadRef { } /** An instruction that writes a variable. */ class WriteAccess extends VariableAccess, @cil_write_access { + /** Gets the `Expr` whose value is used in this variable write. */ Expr getExpr() { none() } } diff --git a/csharp/ql/src/semmle/code/csharp/Callable.qll b/csharp/ql/src/semmle/code/csharp/Callable.qll index 3d1eb96e806..721b5893194 100644 --- a/csharp/ql/src/semmle/code/csharp/Callable.qll +++ b/csharp/ql/src/semmle/code/csharp/Callable.qll @@ -437,6 +437,9 @@ class Operator extends Callable, Member, Attributable, @operator { override string getName() { operators(this, _, result, _, _, _) } + /** + * Gets the metadata name of the operator, such as `op_implicit` or `op_RightShift`. + */ string getFunctionName() { none() } override ValueOrRefType getDeclaringType() { operators(this, _, _, result, _, _) } diff --git a/csharp/ql/src/semmle/code/csharp/Conversion.qll b/csharp/ql/src/semmle/code/csharp/Conversion.qll index 60abdfbebed..75c24c89657 100644 --- a/csharp/ql/src/semmle/code/csharp/Conversion.qll +++ b/csharp/ql/src/semmle/code/csharp/Conversion.qll @@ -514,6 +514,11 @@ predicate convNullableType(ValueOrRefType fromType, NullableType toType) { ) } +/** + * Holds if `fromType` is `NullType`, and `toType` is a type that can represent + * the `null` value, such as a reference type, `Nullable` or a type parameter + * with contraints that restrict it to a reference type. + */ // This is a deliberate, small Cartesian product, so we have manually lifted it to force the // evaluator to evaluate it in its entirety, rather than trying to optimize it in context. pragma[noinline] diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll b/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll index a6d8a0ac9fa..22758fce4ab 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/RuntimeCallable.qll @@ -26,6 +26,7 @@ class RuntimeMethod extends RuntimeCallable { this instanceof CIL::Method } + /** Holds if the method is `static`. */ predicate isStatic() { this.(Method).isStatic() or this.(CIL::Method).isStatic() } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index d410dd06561..c833f6fa868 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -1011,6 +1011,7 @@ class RangeExpr extends Expr, @range_expr { /** An index expression, for example `^1` meaning "1 from the end". */ class IndexExpr extends Expr, @index_expr { + /** Gets the sub expression of this `IndexExpr`. */ Expr getExpr() { result.getParent() = this } override string toString() { result = "^..." } diff --git a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll index f2262f2c4b5..4c9970e2adb 100644 --- a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll +++ b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll @@ -222,6 +222,10 @@ predicate shareFieldOrProperty(ValueOrRefType t, Method m1, Method m2) { ) } +/** + * Holds if `Method` `m` is declared in `ValueOrRefType` `t`, and if there's a + * `FieldAccess` or `PropertyAccess` in `m` that accesses `Declaration` `d`. + */ predicate methodUsesFieldOrProperty(ValueOrRefType t, Method m, Declaration d) { m.getDeclaringType() = t and ( From 8a4754f8d75ad97d962f7e51aff85a18bf7802ce Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 11:48:02 +0200 Subject: [PATCH 100/146] C#: Add missing QlDoc for frameworks --- .../semmle/code/csharp/frameworks/EntityFramework.qll | 9 +++++++++ csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll | 2 ++ .../ql/src/semmle/code/csharp/frameworks/NHibernate.qll | 5 +++++ .../ql/src/semmle/code/csharp/frameworks/system/Linq.qll | 1 + .../semmle/code/csharp/frameworks/system/data/Common.qll | 1 + .../semmle/code/csharp/frameworks/system/data/Entity.qll | 2 ++ .../code/csharp/frameworks/system/linq/Expressions.qll | 1 + .../csharp/frameworks/system/text/RegularExpressions.qll | 4 ++++ .../semmle/code/csharp/frameworks/system/xml/XPath.qll | 1 + 9 files changed, 26 insertions(+) diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll index b81b3669cde..4c7c7c03e69 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll @@ -8,7 +8,9 @@ private import semmle.code.csharp.frameworks.system.collections.Generic private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.dataflow.LibraryTypeDataFlow +/** Definitions relating to the `System.ComponentModel.DataAnnotations`. */ module DataAnnotations { + /** Class for `NotMappedAttribute`. */ class NotMappedAttribute extends Attribute { NotMappedAttribute() { this @@ -18,6 +20,10 @@ module DataAnnotations { } } +/** + * Definitions relating to the `Microsoft.EntityFrameworkCore` or + * `System.Data.Entity`. + */ module EntityFramework { /** An EF6 or EFCore namespace. */ class EFNamespace extends Namespace { @@ -43,12 +49,14 @@ module EntityFramework { class DbContext extends EFClass { DbContext() { this.getName() = "DbContext" } + /** Gets a `Find` or `FindAsync` method in the `DbContext`. */ Method getAFindMethod() { result = this.getAMethod("Find") or result = this.getAMethod("FindAsync") } + /** Gets an `Update` method in the `DbContext`. */ Method getAnUpdateMethod() { result = this.getAMethod("Update") } } @@ -119,6 +127,7 @@ module EntityFramework { preservesValue = false } + /** Gets a conversion operator from `string` to `RawSqlString`. */ ConversionOperator getAConversionTo() { result = this.getAMember() and result.getTargetType() instanceof RawSqlStringStruct and diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll index 1152a69e402..54019d13216 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/JsonNET.qll @@ -135,8 +135,10 @@ module JsonNET { class JsonSerializerClass extends JsonClass, LibraryTypeDataFlow { JsonSerializerClass() { this.hasName("JsonSerializer") } + /** Gets the method for `JsonSerializer.Serialize`. */ Method getSerializeMethod() { result = this.getAMethod("Serialize") } + /** Gets the method for `JsonSerializer.Deserialize`. */ Method getDeserializeMethod() { result = this.getAMethod("Deserialize") } override predicate callableFlow( diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll b/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll index a75b7b0b349..3e46bd13047 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/NHibernate.qll @@ -1,8 +1,13 @@ +/** + * Classes for modelling NHibernate. + */ + import csharp private import semmle.code.csharp.frameworks.System private import semmle.code.csharp.frameworks.system.Collections private import semmle.code.csharp.frameworks.Sql +/** Definitions relating to the `NHibernate` package. */ module NHibernate { /** A class that is mapped to the database. */ abstract class MappedClass extends Class { } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll index d5b7d4cff4e..5f92060eaad 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.System as System +/** Definitions relating to the `System.Linq`. */ module SystemLinq { /** The `System.Linq` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll index 1ccbd5e1e7e..3ce97160ddf 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Data as Data +/** Definitions relating to the `System.Data.Common`. */ module SystemDataCommon { /** The `System.Data.Common` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll index 45dcda1b776..f172e96ea7d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Data as Data +/** Definitions relating to the `System.Data.Entity`. */ module SystemDataEntity { /** The `System.Data.Entity` namespace. */ class Namespace extends csharp::Namespace { @@ -78,6 +79,7 @@ module SystemDataEntity { } } +/** Definitions relating to the `System.Data.Entity.Infrastructure`. */ module SystemDataEntityInfrastructure { /** The `System.Data.Entity.Infrastructure` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll index 1254b855253..5cbc279bf4a 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll @@ -5,6 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Linq +/** Definitions relating to the `System.Linq.Expressions`. */ module SystemLinqExpressions { /** The `System.Linq.Expressions` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll index ce03f5275d9..1820192da11 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/text/RegularExpressions.qll @@ -1,3 +1,7 @@ +/** + * Provides classes related to the namespace `System.Text.RegularExpressions`. + */ + import default import semmle.code.csharp.frameworks.system.Text diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll index dd0b7a4f5e9..d202350d035 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll @@ -3,6 +3,7 @@ import csharp as csharp private import semmle.code.csharp.frameworks.system.Xml as xml +/** Definitions relating to the `System.Xml.XPath`. */ module SystemXmlXPath { /** The `System.Xml.XPath` namespace. */ class Namespace extends csharp::Namespace { From 3f54e5d310aed44988657dd4c0a066b0faf6d9bc Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 15:12:11 +0200 Subject: [PATCH 101/146] Add change note --- change-notes/1.26/analysis-csharp.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/change-notes/1.26/analysis-csharp.md b/change-notes/1.26/analysis-csharp.md index 5580938dc2a..f11696296a2 100644 --- a/change-notes/1.26/analysis-csharp.md +++ b/change-notes/1.26/analysis-csharp.md @@ -19,6 +19,8 @@ The following changes in version 1.26 affect C# analysis in all applications. ## Changes to code extraction * Partial method bodies are extracted. Previously, partial method bodies were skipped completely. +* Inferring the lengths of implicitely sized arrays is fixed. Previously, multi dimensional arrays were always extracted with the same length for +each dimension. With the fix, the array sizes `2` and `1` are extracted for `new int[,]{{1},{2}}`. Previously `2` and `2` were extracted. ## Changes to libraries From 89305865d071b68b1dd71820676121850ab0e6e3 Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 26 Aug 2020 15:41:54 +0200 Subject: [PATCH 102/146] JS: make sanitization a "common" technique rather than "important" --- .../IncompleteHtmlAttributeSanitization.qhelp | 10 +++++++++- .../Security/CWE-116/IncompleteSanitization.qhelp | 10 +++++++++- .../src/Security/CWE-116/UnsafeHtmlExpansion.qhelp | 13 +++++++++++-- .../TypeConfusionThroughParameterTampering.qhelp | 11 ++++++++++- .../Security/CWE-020/IncompleteHostnameRegExp.qhelp | 2 +- .../IncompleteUrlSubstringSanitization.qhelp | 2 +- 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp index 96d821e30e4..a2da6c39f83 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp @@ -6,7 +6,7 @@

    - Sanitizing untrusted input for HTML meta-characters is an important + Sanitizing untrusted input for HTML meta-characters is a common technique for preventing cross-site scripting attacks. Usually, this is done by escaping <, >, & and ". However, the context in which @@ -38,6 +38,14 @@

    +

    + + An even safer alternative is to design the application + such that sanitization isn't needed at all, for instance by using HTML + templates that are explicit about the values they treat as HTML. + +

    + diff --git a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp index 3cc58d0e0e5..ec5f7d784af 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp @@ -5,7 +5,7 @@

    -Sanitizing untrusted input is an important technique for preventing injection attacks such as +Sanitizing untrusted input is a common technique for preventing injection attacks such as SQL injection or cross-site scripting. Usually, this is done by escaping meta-characters such as quotes in a domain-specific way so that they are treated as normal characters.

    @@ -31,6 +31,14 @@ still have undesirable effects, such as badly rendered or confusing output. Use a (well-tested) sanitization library if at all possible. These libraries are much more likely to handle corner cases correctly than a custom implementation.

    + +

    + +An even safer alternative is to design the application such that sanitization isn't +needed at all, for instance by using prepared statements for SQL queries. + +

    +

    Otherwise, make sure to use a regular expression with the g flag to ensure that all occurrences are replaced, and remember to escape backslashes if applicable. diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp index e0a070e6669..7bda06f7f0e 100644 --- a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp @@ -6,8 +6,8 @@

    - Sanitizing untrusted input for HTML meta-characters is an - important technique for preventing cross-site scripting attacks. But + Sanitizing untrusted input for HTML meta-characters is a + common technique for preventing cross-site scripting attacks. But even a sanitized input can be dangerous to use if it is modified further before a browser treats it as HTML. @@ -28,6 +28,15 @@ them as HTML.

    + +

    + + An even safer alternative is to design the application + such that sanitization isn't needed at all, for instance by using HTML + templates that are explicit about the values they treat as HTML. + +

    + diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp index 314ab2f4ed7..7713c25c292 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp @@ -4,7 +4,7 @@

    - Sanitizing untrusted HTTP request parameters is an important + Sanitizing untrusted HTTP request parameters is a common technique for preventing injection attacks such as SQL injection or path traversal. This is sometimes done by checking if the request parameters contain blacklisted substrings. @@ -35,6 +35,15 @@ is user-controlled.

    + +

    + + An even safer alternative is to design the application such that sanitization isn't + needed at all, for instance by using prepared statements for SQL queries. + +

    + + diff --git a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp index 8eb0f43eb01..d112cbca508 100644 --- a/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp +++ b/python/ql/src/Security/CWE-020/IncompleteHostnameRegExp.qhelp @@ -6,7 +6,7 @@

    - Sanitizing untrusted URLs is an important technique for + Sanitizing untrusted URLs is a common technique for preventing attacks such as request forgeries and malicious redirections. Often, this is done by checking that the host of a URL is in a set of allowed hosts. diff --git a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp index 2723c1448b1..87b21ef1ec2 100644 --- a/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp +++ b/python/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qhelp @@ -6,7 +6,7 @@

    - Sanitizing untrusted URLs is an important technique for + Sanitizing untrusted URLs is a common technique for preventing attacks such as request forgeries and malicious redirections. Usually, this is done by checking that the host of a URL is in a set of allowed hosts. From 18c65e9f73b22d1c13f024ea7bf9d42e1acd180f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 26 Aug 2020 15:57:41 +0200 Subject: [PATCH 103/146] Fix typo in change notes --- change-notes/1.26/analysis-csharp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change-notes/1.26/analysis-csharp.md b/change-notes/1.26/analysis-csharp.md index f11696296a2..202c939553b 100644 --- a/change-notes/1.26/analysis-csharp.md +++ b/change-notes/1.26/analysis-csharp.md @@ -19,7 +19,7 @@ The following changes in version 1.26 affect C# analysis in all applications. ## Changes to code extraction * Partial method bodies are extracted. Previously, partial method bodies were skipped completely. -* Inferring the lengths of implicitely sized arrays is fixed. Previously, multi dimensional arrays were always extracted with the same length for +* Inferring the lengths of implicitely sized arrays is fixed. Previously, multidimensional arrays were always extracted with the same length for each dimension. With the fix, the array sizes `2` and `1` are extracted for `new int[,]{{1},{2}}`. Previously `2` and `2` were extracted. ## Changes to libraries From e193e12b3f28d647dde1e0806f6f4c36cda65e33 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Wed, 26 Aug 2020 16:10:04 +0200 Subject: [PATCH 104/146] Python: Add support for inline test expectations library --- .../TestUtilities/InlineExpectationsTest.qll | 290 ++++++++++++++++++ .../InlineExpectationsTestPrivate.qll | 7 + 2 files changed, 297 insertions(+) create mode 100644 python/ql/test/TestUtilities/InlineExpectationsTest.qll create mode 100644 python/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll diff --git a/python/ql/test/TestUtilities/InlineExpectationsTest.qll b/python/ql/test/TestUtilities/InlineExpectationsTest.qll new file mode 100644 index 00000000000..150c898bdbd --- /dev/null +++ b/python/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -0,0 +1,290 @@ +/** + * 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 valuesasas + * ) { + * exists(Expr e | + * tag = "const" and // The tag for this test. + * valuesasas = 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 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, as long as each is prefixed by a `$`. 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 false positives and false negatives, it is possible to further + * annotate that a particular expected result is known to be a false positive, or that a particular + * missing result is known to be a false negative: + * + * `$f+:tag=expected-value` // False positive + * `$f-:tag=expected-value` // False negative + * + * A false positive 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 false positive: tag=value". A + * false negative 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 false negative: tag=value". + * + * 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 false negative:" + 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 false positive:" + 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*(\\$(?:[^/]|/[^/])*)(?://.*)?" } + +/** + * RegEx pattern to match a single expected result, not including the leading `$`. It starts with an + * optional `f+:` or `f-:`, followed by one or more comma-separated tags containing only letters, + * `-`, and `_`, optionally followed by `=` and the expected value. + */ +private string expectationPattern() { + result = "(?:(f(?:\\+|-)):)?((?:[A-Za-z-_]+)(?:\\s*,\\s*[A-Za-z-_]+)*)(?:=(.*))?" +} + +private string getAnExpectation(LineComment comment) { + result = comment.getContents().regexpCapture(expectationCommentPattern(), 1).splitAt("$").trim() and + result != "" +} + +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(string expectation | + expectation = getAnExpectation(comment) and + expectation.regexpMatch(expectationPattern()) and + tag = expectation.regexpCapture(expectationPattern(), 2).splitAt(",").trim() and + ( + if exists(expectation.regexpCapture(expectationPattern(), 3)) + then value = expectation.regexpCapture(expectationPattern(), 3) + else value = "" + ) and + ( + if exists(expectation.regexpCapture(expectationPattern(), 1)) + then knownFailure = expectation.regexpCapture(expectationPattern(), 1) + else knownFailure = "" + ) + ) + } or + TInvalidExpectation(LineComment comment, string expectation) { + expectation = getAnExpectation(comment) 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() + } +} + +class GoodExpectation extends ValidExpectation { + GoodExpectation() { getKnownFailure() = "" } +} + +class FalsePositiveExpectation extends ValidExpectation { + FalsePositiveExpectation() { getKnownFailure() = "f+" } +} + +class FalseNegativeExpectation extends ValidExpectation { + FalseNegativeExpectation() { getKnownFailure() = "f-" } +} + +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/python/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll b/python/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll new file mode 100644 index 00000000000..aaea45a3cce --- /dev/null +++ b/python/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll @@ -0,0 +1,7 @@ +import python + +/** + * A class representing line comments in Python. As this is the only form of comment Python + * permits, we simply reuse the `Comment` class. + */ +class LineComment = Comment; From dcabd37974e6648b36960b9e1812ce0a5ea803ef Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Wed, 26 Aug 2020 17:58:35 +0200 Subject: [PATCH 105/146] Python: Update test expectations --- .../dataflow/tainttracking/basic/LocalTaintStep.expected | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected b/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected index b23839170ff..6b47e072628 100644 --- a/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected +++ b/python/ql/test/experimental/dataflow/tainttracking/basic/LocalTaintStep.expected @@ -1,5 +1,3 @@ -| test.py:0:0:0:0 | SSA variable $ | test.py:0:0:0:0 | Exit node for Module test | | test.py:7:5:7:16 | SSA variable also_tainted | test.py:8:5:8:22 | SSA variable also_tainted | | test.py:7:5:7:16 | SSA variable also_tainted | test.py:8:10:8:21 | ControlFlowNode for also_tainted | | test.py:7:20:7:25 | ControlFlowNode for SOURCE | test.py:7:5:7:16 | SSA variable also_tainted | -| test.py:8:5:8:22 | SSA variable also_tainted | test.py:6:1:6:11 | Exit node for Function func | From d27442e8466263674c953d7a4b39468a93b1ff4e Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Wed, 26 Aug 2020 20:18:54 +0200 Subject: [PATCH 106/146] Apply suggestions from code review Co-authored-by: Felicity Chapman --- .../CWE-116/IncompleteHtmlAttributeSanitization.qhelp | 2 +- .../ql/src/Security/CWE-116/IncompleteSanitization.qhelp | 4 ++-- javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp | 2 +- .../CWE-843/TypeConfusionThroughParameterTampering.qhelp | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp index a2da6c39f83..7abe4844dfd 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-116/IncompleteHtmlAttributeSanitization.qhelp @@ -41,7 +41,7 @@

    An even safer alternative is to design the application - such that sanitization isn't needed at all, for instance by using HTML + so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML.

    diff --git a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp index ec5f7d784af..0ea141309f4 100644 --- a/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp +++ b/javascript/ql/src/Security/CWE-116/IncompleteSanitization.qhelp @@ -34,8 +34,8 @@ likely to handle corner cases correctly than a custom implementation.

    -An even safer alternative is to design the application such that sanitization isn't -needed at all, for instance by using prepared statements for SQL queries. +An even safer alternative is to design the application so that sanitization is not +needed, for instance by using prepared statements for SQL queries.

    diff --git a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp index 7bda06f7f0e..3a70e87933c 100644 --- a/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp +++ b/javascript/ql/src/Security/CWE-116/UnsafeHtmlExpansion.qhelp @@ -32,7 +32,7 @@

    An even safer alternative is to design the application - such that sanitization isn't needed at all, for instance by using HTML + so that sanitization is not needed, for instance by using HTML templates that are explicit about the values they treat as HTML.

    diff --git a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp index 7713c25c292..d5e3963755d 100644 --- a/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp +++ b/javascript/ql/src/Security/CWE-843/TypeConfusionThroughParameterTampering.qhelp @@ -38,8 +38,8 @@

    - An even safer alternative is to design the application such that sanitization isn't - needed at all, for instance by using prepared statements for SQL queries. + An even safer alternative is to design the application so that sanitization is not + needed, for instance by using prepared statements for SQL queries.

    From 3f6eef8437cd7f4aa76c28ac84ea6aeb28151325 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 12 May 2020 22:45:48 +0530 Subject: [PATCH 107/146] Java: add websocket reads as remote flow source. Currently, JAX-WS reads are considered as untrusted. However, `java.net.http.WebSocket` reads are not marked as such. This PR adds support for the same. --- .../semmle/code/java/dataflow/FlowSources.qll | 9 +++++++ .../code/java/frameworks/javase/WebSocket.qll | 21 +++++++++++++++ .../CWE-079/semmle/tests/WebsocketXss.java | 27 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll create mode 100644 java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 1d8de8ea471..b6d367bc32c 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -15,6 +15,7 @@ import semmle.code.java.frameworks.ApacheHttp import semmle.code.java.frameworks.android.XmlParsing import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.JaxWS +import semmle.code.java.frameworks.javase.WebSocket import semmle.code.java.frameworks.android.Intent import semmle.code.java.frameworks.spring.SpringWeb import semmle.code.java.frameworks.spring.SpringController @@ -155,6 +156,14 @@ private class ThriftIfaceParameterSource extends RemoteFlowSource { override string getSourceType() { result = "Thrift Iface parameter" } } +private class WebSocketMessageParameterSource extends RemoteFlowSource { + WebSocketMessageParameterSource() { + exists(WebsocketOnText t | t.getParameter(1) = this.asParameter()) + } + + override string getSourceType() { result = "Websocket onText parameter" } +} + /** Class for `tainted` user input. */ abstract class UserInput extends DataFlow::Node { } diff --git a/java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll b/java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll new file mode 100644 index 00000000000..17d3d4579d2 --- /dev/null +++ b/java/ql/src/semmle/code/java/frameworks/javase/WebSocket.qll @@ -0,0 +1,21 @@ +/** + * Provides classes for identifying methods called by the Java SE WebSocket package. + */ + +import java + +/** The `java.net.http.Websocket.Listener` interface. */ +class WebsocketListener extends Interface { + WebsocketListener() { this.hasQualifiedName("java.net.http", "WebSocket$Listener") } +} + +/** The method `onText` on a type that implements the `java.net.http.Websocket.Listener` interface. */ +class WebsocketOnText extends Method { + WebsocketOnText() { + exists(WebsocketListener l | + this.getDeclaringType().extendsOrImplements(l) and + // onText(WebSocket webSocket, CharSequence data, boolean last) + this.hasName("onText") + ) + } +} diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java new file mode 100644 index 00000000000..2fc9998b775 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java @@ -0,0 +1,27 @@ +// package test.cwe079.cwe.examples; + +// import java.net.http.HttpClient; +// import java.net.http.WebSocket; +// import java.net.URI; +// import java.util.*; +// import java.util.concurrent.*; + +// public class WebsocketXss { +// public static void main(String[] args) throws Exception { +// WebSocket.Listener listener = new WebSocket.Listener() { +// public CompletionStage onText(WebSocket webSocket, CharSequence message, boolean last) { +// try { +// HttpClient client = HttpClient.newBuilder().build(); +// CompletableFuture ws = client.newWebSocketBuilder() +// .buildAsync(URI.create("ws://websocket.example.com"), null); +// ws.get().sendText​(message, false); +// } catch (Exception e) { +// // TODO: handle exception +// } + +// return null; +// }; +// }; + +// } +// } \ No newline at end of file From dcf51c75e9f019de168e6d2d82ba56efc43abbe3 Mon Sep 17 00:00:00 2001 From: Alessio Della Libera <43420907+dellalibera@users.noreply.github.com> Date: Wed, 26 Aug 2020 23:33:52 +0200 Subject: [PATCH 108/146] Update javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql Co-authored-by: Esben Sparre Andreasen --- .../ql/src/experimental/Security/CWE-614/InsecureCookie.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index d735399bfb0..4aee64573fb 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -15,5 +15,5 @@ import InsecureCookie::Cookie from Cookie cookie where not cookie.isSecure() -select "Cookie is added to response without the 'secure' flag being set to true (using " + +select cookie, "Cookie is added to response without the 'secure' flag being set to true" cookie.getKind() + ").", cookie From cd1d50b63791d7e7834067da76f35e34f48973db Mon Sep 17 00:00:00 2001 From: ubuntu <43420907+dellalibera@users.noreply.github.com> Date: Wed, 26 Aug 2020 23:50:15 +0200 Subject: [PATCH 109/146] Update expected output --- .../Security/CWE-614/InsecureCookie.ql | 1 - .../Security/CWE-614/InsecureCookies.expected | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql index 4aee64573fb..69b3afb1c7f 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.ql @@ -16,4 +16,3 @@ import InsecureCookie::Cookie from Cookie cookie where not cookie.isSecure() select cookie, "Cookie is added to response without the 'secure' flag being set to true" - cookie.getKind() + ").", cookie diff --git a/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected b/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected index de25e9b58ed..fc98205a151 100644 --- a/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected +++ b/javascript/ql/test/query-tests/Security/CWE-614/InsecureCookies.expected @@ -1,9 +1,9 @@ -| Cookie is added to response without the 'secure' flag being set to true (using cookie-session). | test_cookie-session.js:18:9:28:2 | session ... }\\n}) | -| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:5:9:8:2 | session ... T OK\\n}) | -| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:10:9:13:2 | session ... T OK\\n}) | -| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:15:9:18:2 | session ... T OK\\n}) | -| Cookie is added to response without the 'secure' flag being set to true (using express-session). | test_express-session.js:25:9:25:21 | session(sess) | -| Cookie is added to response without the 'secure' flag being set to true (using js-cookie). | test_jscookie.js:2:1:2:48 | js_cook ... alse }) | -| Cookie is added to response without the 'secure' flag being set to true (using response.cookie). | test_responseCookie.js:5:5:10:10 | res.coo ... }) | -| Cookie is added to response without the 'secure' flag being set to true (using response.cookie). | test_responseCookie.js:20:5:20:40 | res.coo ... ptions) | -| Cookie is added to response without the 'secure' flag being set to true (using set-cookie header). | test_httpserver.js:7:37:7:73 | ["type= ... cript"] | +| test_cookie-session.js:18:9:28:2 | session ... }\\n}) | Cookie is added to response without the 'secure' flag being set to true | +| test_express-session.js:5:9:8:2 | session ... T OK\\n}) | Cookie is added to response without the 'secure' flag being set to true | +| test_express-session.js:10:9:13:2 | session ... T OK\\n}) | Cookie is added to response without the 'secure' flag being set to true | +| test_express-session.js:15:9:18:2 | session ... T OK\\n}) | Cookie is added to response without the 'secure' flag being set to true | +| test_express-session.js:25:9:25:21 | session(sess) | Cookie is added to response without the 'secure' flag being set to true | +| test_httpserver.js:7:37:7:73 | ["type= ... cript"] | Cookie is added to response without the 'secure' flag being set to true | +| test_jscookie.js:2:1:2:48 | js_cook ... alse }) | Cookie is added to response without the 'secure' flag being set to true | +| test_responseCookie.js:5:5:10:10 | res.coo ... }) | Cookie is added to response without the 'secure' flag being set to true | +| test_responseCookie.js:20:5:20:40 | res.coo ... ptions) | Cookie is added to response without the 'secure' flag being set to true | From 09025c2198b47c4596aa63971239677bb67c3ec1 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Thu, 27 Aug 2020 08:40:13 +0200 Subject: [PATCH 110/146] Python: Fix test, update results and annotations --- .../coverage/argumentRouting1.expected | 16 +++ .../dataflow/coverage/argumentRouting1.ql | 5 +- .../coverage/argumentRouting2.expected | 16 +++ .../coverage/argumentRouting3.expected | 1 + .../experimental/dataflow/coverage/classes.py | 98 +++++++++---------- 5 files changed, 85 insertions(+), 51 deletions(-) diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected index e69de29bb2d..1bb41afa870 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.expected @@ -0,0 +1,16 @@ +| classes.py:620:5:620:16 | SSA variable with_getitem | classes.py:614:15:614:18 | ControlFlowNode for self | +| classes.py:637:5:637:16 | SSA variable with_setitem | classes.py:632:15:632:18 | ControlFlowNode for self | +| classes.py:654:5:654:16 | SSA variable with_delitem | classes.py:649:15:649:18 | ControlFlowNode for self | +| classes.py:735:5:735:12 | SSA variable with_add | classes.py:729:15:729:18 | ControlFlowNode for self | +| classes.py:752:5:752:12 | SSA variable with_sub | classes.py:746:15:746:18 | ControlFlowNode for self | +| classes.py:769:5:769:12 | SSA variable with_mul | classes.py:763:15:763:18 | ControlFlowNode for self | +| classes.py:786:5:786:15 | SSA variable with_matmul | classes.py:780:15:780:18 | ControlFlowNode for self | +| classes.py:803:5:803:16 | SSA variable with_truediv | classes.py:797:15:797:18 | ControlFlowNode for self | +| classes.py:820:5:820:17 | SSA variable with_floordiv | classes.py:814:15:814:18 | ControlFlowNode for self | +| classes.py:837:5:837:12 | SSA variable with_mod | classes.py:831:15:831:18 | ControlFlowNode for self | +| classes.py:877:5:877:12 | SSA variable with_pow | classes.py:865:15:865:18 | ControlFlowNode for self | +| classes.py:894:5:894:15 | SSA variable with_lshift | classes.py:888:15:888:18 | ControlFlowNode for self | +| classes.py:911:5:911:15 | SSA variable with_rshift | classes.py:905:15:905:18 | ControlFlowNode for self | +| classes.py:928:5:928:12 | SSA variable with_and | classes.py:922:15:922:18 | ControlFlowNode for self | +| classes.py:945:5:945:12 | SSA variable with_xor | classes.py:939:15:939:18 | ControlFlowNode for self | +| classes.py:962:5:962:11 | SSA variable with_or | classes.py:956:15:956:18 | ControlFlowNode for self | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql index 79bed33d4c7..94d63e6f978 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql @@ -7,9 +7,10 @@ class ArgumentRoutingConfig extends DataFlow::Configuration { ArgumentRoutingConfig() { this = "ArgumentRoutingConfig" } override predicate isSource(DataFlow::Node node) { - exists(AssignmentDefinition def | + exists(AssignmentDefinition def, DataFlow::DataFlowCall call | def.getVariable() = node.(DataFlow::EssaNode).getVar() and - def.getValue().(DataFlow::DataFlowCall).getCallable().getName().matches("With\\_%") + def.getValue() = call.getNode() and + call.getCallable().getName().matches("With\\_%") ) and node.(DataFlow::EssaNode).getVar().getName().matches("with\\_%") } diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected index e69de29bb2d..79ae2de5c94 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting2.expected @@ -0,0 +1,16 @@ +| classes.py:622:18:622:21 | ControlFlowNode for arg2 | classes.py:613:15:613:17 | ControlFlowNode for key | +| classes.py:640:18:640:21 | ControlFlowNode for arg2 | classes.py:631:15:631:17 | ControlFlowNode for key | +| classes.py:656:22:656:25 | ControlFlowNode for arg2 | classes.py:648:15:648:17 | ControlFlowNode for key | +| classes.py:737:16:737:19 | ControlFlowNode for arg2 | classes.py:728:15:728:19 | ControlFlowNode for other | +| classes.py:754:16:754:19 | ControlFlowNode for arg2 | classes.py:745:15:745:19 | ControlFlowNode for other | +| classes.py:771:16:771:19 | ControlFlowNode for arg2 | classes.py:762:15:762:19 | ControlFlowNode for other | +| classes.py:788:19:788:22 | ControlFlowNode for arg2 | classes.py:779:15:779:19 | ControlFlowNode for other | +| classes.py:805:20:805:23 | ControlFlowNode for arg2 | classes.py:796:15:796:19 | ControlFlowNode for other | +| classes.py:822:22:822:25 | ControlFlowNode for arg2 | classes.py:813:15:813:19 | ControlFlowNode for other | +| classes.py:839:16:839:19 | ControlFlowNode for arg2 | classes.py:830:15:830:19 | ControlFlowNode for other | +| classes.py:879:17:879:20 | ControlFlowNode for arg2 | classes.py:864:15:864:19 | ControlFlowNode for other | +| classes.py:896:20:896:23 | ControlFlowNode for arg2 | classes.py:887:15:887:19 | ControlFlowNode for other | +| classes.py:913:20:913:23 | ControlFlowNode for arg2 | classes.py:904:15:904:19 | ControlFlowNode for other | +| classes.py:930:16:930:19 | ControlFlowNode for arg2 | classes.py:921:15:921:19 | ControlFlowNode for other | +| classes.py:947:16:947:19 | ControlFlowNode for arg2 | classes.py:938:15:938:19 | ControlFlowNode for other | +| classes.py:964:15:964:18 | ControlFlowNode for arg2 | classes.py:955:15:955:19 | ControlFlowNode for other | diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected b/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected index e69de29bb2d..d2b9bb03301 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting3.expected @@ -0,0 +1 @@ +| classes.py:640:26:640:29 | ControlFlowNode for arg3 | classes.py:630:15:630:19 | ControlFlowNode for value | diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 3f95ff3ac4b..5039a65181d 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -610,9 +610,9 @@ def test_length_hint(): class With_getitem: def __getitem__(self, key): - SINK2(key) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(key) + SINK1(self) + OK() return "" @@ -627,10 +627,10 @@ def test_getitem(): class With_setitem: def __setitem__(self, key, value): - SINK3(value) # Flow not found - SINK2(key) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK3(value) + SINK2(key) + SINK1(self) + OK() def test_setitem(): @@ -645,9 +645,9 @@ def test_setitem(): class With_delitem: def __delitem__(self, key): - SINK2(key) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(key) + SINK1(self) + OK() def test_delitem(): @@ -725,9 +725,9 @@ def test_contains(): class With_add: def __add__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -742,9 +742,9 @@ def test_add(): class With_sub: def __sub__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -759,9 +759,9 @@ def test_sub(): class With_mul: def __mul__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -776,9 +776,9 @@ def test_mul(): class With_matmul: def __matmul__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -793,9 +793,9 @@ def test_matmul(): class With_truediv: def __truediv__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -810,9 +810,9 @@ def test_truediv(): class With_floordiv: def __floordiv__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -827,9 +827,9 @@ def test_floordiv(): class With_mod: def __mod__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -861,9 +861,9 @@ def test_divmod(): class With_pow: def __pow__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -884,9 +884,9 @@ def test_pow_op(): class With_lshift: def __lshift__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -901,9 +901,9 @@ def test_lshift(): class With_rshift: def __rshift__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -918,9 +918,9 @@ def test_rshift(): class With_and: def __and__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -935,9 +935,9 @@ def test_and(): class With_xor: def __xor__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self @@ -952,9 +952,9 @@ def test_xor(): class With_or: def __or__(self, other): - SINK2(other) # Flow not found - SINK1(self) # Flow not found - OK() # Call not found + SINK2(other) + SINK1(self) + OK() return self From 2ac732c50a2692cf24e8e78c6834feb6cc5b4964 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 26 Aug 2020 20:11:54 +0200 Subject: [PATCH 111/146] C#: Teach autobuilder about `VsDevCmd.bat` --- .../BuildScripts.cs | 11 ++++++++-- .../Semmle.Autobuild.Shared/BuildTools.cs | 21 ++++++++++--------- .../Semmle.Autobuild.Shared/MsBuildRule.cs | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs index 95c5feaa704..4656f51a4bb 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/BuildScripts.cs @@ -450,15 +450,22 @@ Microsoft.NETCore.App 2.2.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.Ap Actions.GetEnvironmentVariable["ProgramFiles(x86)"] = @"C:\Program Files (x86)"; Actions.FileExists[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"] = true; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = 0; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2"; - Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0"; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationPath"] = "C:\\VS1\nC:\\VS2\nC:\\VS3"; Actions.RunProcess[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = 0; + Actions.RunProcessOut[@"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe -prerelease -legacy -property installationVersion"] = "10.0\n11.0\n16.0"; var candidates = BuildTools.GetCandidateVcVarsFiles(Actions).ToArray(); Assert.Equal("C:\\VS1\\VC\\vcvarsall.bat", candidates[0].Path); Assert.Equal(10, candidates[0].ToolsVersion); Assert.Equal("C:\\VS2\\VC\\vcvarsall.bat", candidates[1].Path); Assert.Equal(11, candidates[1].ToolsVersion); + Assert.Equal(@"C:\VS3\VC\Auxiliary\Build\vcvars32.bat", candidates[2].Path); + Assert.Equal(16, candidates[2].ToolsVersion); + Assert.Equal(@"C:\VS3\VC\Auxiliary\Build\vcvars64.bat", candidates[3].Path); + Assert.Equal(16, candidates[3].ToolsVersion); + Assert.Equal(@"C:\VS3\Common7\Tools\VsDevCmd.bat", candidates[4].Path); + Assert.Equal(16, candidates[4].ToolsVersion); + Assert.Equal(5, candidates.Length); } [Fact] diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs index d1aab3c4551..7f655a3f215 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs @@ -11,13 +11,11 @@ namespace Semmle.Autobuild.Shared { public readonly int ToolsVersion; public readonly string Path; - public readonly string[] Platform; - public VcVarsBatFile(string path, int version, params string[] platform) + public VcVarsBatFile(string path, int version) { Path = path; ToolsVersion = version; - Platform = platform; } }; @@ -51,12 +49,15 @@ namespace Semmle.Autobuild.Shared { if (majorVersion < 15) { - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion, "x86"); + // Visual Studio 2015 and below + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\vcvarsall.bat"), majorVersion); } else { - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion, "x64"); + // Visual Studio 2017 and above + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars32.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"VC\Auxiliary\Build\vcvars64.bat"), majorVersion); + yield return new VcVarsBatFile(actions.PathCombine(vsInstallation.InstallationPath, @"Common7\Tools\VsDevCmd.bat"), majorVersion); } } // else: Skip installation without a version @@ -66,10 +67,10 @@ namespace Semmle.Autobuild.Shared } // vswhere not installed or didn't run correctly - return legacy Visual Studio versions - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11, "x86"); - yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10, "x86"); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 14.0\VC\vcvarsall.bat"), 14); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 12.0\VC\vcvarsall.bat"), 12); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 11.0\VC\vcvarsall.bat"), 11); + yield return new VcVarsBatFile(actions.PathCombine(programFilesx86, @"Microsoft Visual Studio 10.0\VC\vcvarsall.bat"), 10); } /// diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs index 4994eefab06..2efae82e7e4 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/MsBuildRule.cs @@ -33,7 +33,7 @@ namespace Semmle.Autobuild.Shared if (vsTools == null && builder.Actions.IsWindows()) { - builder.Log(Severity.Warning, "Could not find a suitable version of vcvarsall.bat"); + builder.Log(Severity.Warning, "Could not find a suitable version of VsDevCmd.bat/vcvarsall.bat"); } var nuget = From 9aa1404646a77ac48dbfc6c5445a9e82b031029c Mon Sep 17 00:00:00 2001 From: Esben Sparre Andreasen Date: Thu, 27 Aug 2020 09:44:45 +0200 Subject: [PATCH 112/146] JS: fix formatting of InsecureCookie.qll --- .../experimental/Security/CWE-614/InsecureCookie.qll | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll index 05999853050..7b32c1fce55 100644 --- a/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll +++ b/javascript/ql/src/experimental/Security/CWE-614/InsecureCookie.qll @@ -76,9 +76,7 @@ module Cookie { * A cookie set using `response.cookie` from `express` module (https://expressjs.com/en/api.html#res.cookie). */ class InsecureExpressCookieResponse extends Cookie, DataFlow::MethodCallNode { - InsecureExpressCookieResponse() { - this.calls(any(Express::ResponseExpr r).flow(), "cookie") - } + InsecureExpressCookieResponse() { this.calls(any(Express::ResponseExpr r).flow(), "cookie") } override string getKind() { result = "response.cookie" } @@ -124,10 +122,10 @@ module Cookie { */ class InsecureJsCookie extends Cookie { InsecureJsCookie() { - this = - [DataFlow::globalVarRef("Cookie"), - DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"), - DataFlow::moduleImport("js-cookie")].getAMemberCall("set") + this = + [DataFlow::globalVarRef("Cookie"), + DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"), + DataFlow::moduleImport("js-cookie")].getAMemberCall("set") } override string getKind() { result = "js-cookie" } From 2235c19593986e096f45eba2369b98d09bf906c3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 26 Aug 2020 13:14:27 +0100 Subject: [PATCH 113/146] C++: Add test cases for 'assign' and extra cases for 'data'. --- .../dataflow/taint-tests/localTaint.expected | 127 ++++++++++++++++++ .../library-tests/dataflow/taint-tests/stl.h | 2 + .../dataflow/taint-tests/string.cpp | 9 ++ .../dataflow/taint-tests/taint.expected | 2 + .../dataflow/taint-tests/test_diff.expected | 2 + .../dataflow/taint-tests/vector.cpp | 55 +++++++- 6 files changed, 194 insertions(+), 3 deletions(-) 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 df455e9bdaa..2f5179c15ed 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -717,6 +717,19 @@ | string.cpp:337:9:337:9 | a | string.cpp:337:10:337:10 | call to operator[] | TAINT | | string.cpp:337:9:337:9 | ref arg a | string.cpp:339:7:339:7 | a | | | string.cpp:337:10:337:10 | call to operator[] | string.cpp:337:2:337:12 | ... = ... | | +| string.cpp:346:18:346:22 | 123 | string.cpp:346:18:346:23 | call to basic_string | TAINT | +| string.cpp:346:18:346:23 | call to basic_string | string.cpp:348:2:348:4 | str | | +| string.cpp:346:18:346:23 | call to basic_string | string.cpp:349:7:349:9 | str | | +| string.cpp:346:18:346:23 | call to basic_string | string.cpp:350:7:350:9 | str | | +| string.cpp:348:2:348:4 | ref arg str | string.cpp:349:7:349:9 | str | | +| string.cpp:348:2:348:4 | ref arg str | string.cpp:350:7:350:9 | str | | +| string.cpp:348:2:348:4 | str | string.cpp:348:6:348:9 | call to data | TAINT | +| string.cpp:348:2:348:14 | access to array [post update] | string.cpp:348:6:348:9 | call to data [inner post update] | | +| string.cpp:348:2:348:34 | ... = ... | string.cpp:348:2:348:14 | access to array [post update] | | +| string.cpp:348:6:348:9 | call to data | string.cpp:348:2:348:14 | access to array | TAINT | +| string.cpp:348:13:348:13 | 1 | string.cpp:348:2:348:14 | access to array | TAINT | +| string.cpp:348:18:348:32 | call to source | string.cpp:348:2:348:34 | ... = ... | | +| string.cpp:350:7:350:9 | str | string.cpp:350:11:350:14 | call to data | TAINT | | stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:16:2:16:4 | ss1 | | | stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:22:7:22:9 | ss1 | | | stringstream.cpp:13:20:13:22 | call to basic_stringstream | stringstream.cpp:27:7:27:9 | ss1 | | @@ -2209,3 +2222,117 @@ | vector.cpp:212:8:212:9 | ref arg ff | vector.cpp:213:2:213:2 | ff | | | vector.cpp:212:10:212:10 | call to operator[] [post update] | vector.cpp:212:8:212:9 | ref arg ff | TAINT | | vector.cpp:212:14:212:15 | vs | vector.cpp:212:16:212:16 | call to operator[] | TAINT | +| vector.cpp:219:19:219:20 | call to vector | vector.cpp:221:2:221:3 | v1 | | +| vector.cpp:219:19:219:20 | call to vector | vector.cpp:225:7:225:8 | v1 | | +| vector.cpp:219:19:219:20 | call to vector | vector.cpp:233:13:233:14 | v1 | | +| vector.cpp:219:19:219:20 | call to vector | vector.cpp:233:25:233:26 | v1 | | +| vector.cpp:219:19:219:20 | call to vector | vector.cpp:247:1:247:1 | v1 | | +| vector.cpp:219:23:219:24 | call to vector | vector.cpp:222:2:222:3 | v2 | | +| vector.cpp:219:23:219:24 | call to vector | vector.cpp:226:7:226:8 | v2 | | +| vector.cpp:219:23:219:24 | call to vector | vector.cpp:247:1:247:1 | v2 | | +| vector.cpp:219:27:219:28 | call to vector | vector.cpp:223:2:223:3 | v3 | | +| vector.cpp:219:27:219:28 | call to vector | vector.cpp:227:7:227:8 | v3 | | +| vector.cpp:219:27:219:28 | call to vector | vector.cpp:234:13:234:14 | v3 | | +| vector.cpp:219:27:219:28 | call to vector | vector.cpp:234:25:234:26 | v3 | | +| vector.cpp:219:27:219:28 | call to vector | vector.cpp:235:8:235:9 | v3 | | +| vector.cpp:219:27:219:28 | call to vector | vector.cpp:247:1:247:1 | v3 | | +| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:225:7:225:8 | v1 | | +| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:233:13:233:14 | v1 | | +| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | +| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | +| vector.cpp:222:2:222:3 | ref arg v2 | vector.cpp:226:7:226:8 | v2 | | +| vector.cpp:222:2:222:3 | ref arg v2 | vector.cpp:247:1:247:1 | v2 | | +| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:227:7:227:8 | v3 | | +| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:234:13:234:14 | v3 | | +| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | +| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | +| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | +| vector.cpp:223:15:223:20 | call to source | vector.cpp:223:2:223:3 | ref arg v3 | TAINT | +| vector.cpp:225:7:225:8 | ref arg v1 | vector.cpp:233:13:233:14 | v1 | | +| vector.cpp:225:7:225:8 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | +| vector.cpp:225:7:225:8 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | +| vector.cpp:226:7:226:8 | ref arg v2 | vector.cpp:247:1:247:1 | v2 | | +| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:234:13:234:14 | v3 | | +| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | +| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | +| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | +| vector.cpp:230:20:230:21 | call to vector | vector.cpp:233:3:233:4 | v4 | | +| vector.cpp:230:20:230:21 | call to vector | vector.cpp:241:8:241:9 | v4 | | +| vector.cpp:230:20:230:21 | call to vector | vector.cpp:246:2:246:2 | v4 | | +| vector.cpp:230:24:230:25 | call to vector | vector.cpp:234:3:234:4 | v5 | | +| vector.cpp:230:24:230:25 | call to vector | vector.cpp:242:8:242:9 | v5 | | +| vector.cpp:230:24:230:25 | call to vector | vector.cpp:246:2:246:2 | v5 | | +| vector.cpp:230:28:230:29 | call to vector | vector.cpp:239:3:239:4 | v6 | | +| vector.cpp:230:28:230:29 | call to vector | vector.cpp:245:8:245:9 | v6 | | +| vector.cpp:230:28:230:29 | call to vector | vector.cpp:246:2:246:2 | v6 | | +| vector.cpp:233:3:233:4 | ref arg v4 | vector.cpp:241:8:241:9 | v4 | | +| vector.cpp:233:3:233:4 | ref arg v4 | vector.cpp:246:2:246:2 | v4 | | +| vector.cpp:233:13:233:14 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | +| vector.cpp:233:13:233:14 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | +| vector.cpp:233:25:233:26 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | +| vector.cpp:234:3:234:4 | ref arg v5 | vector.cpp:242:8:242:9 | v5 | | +| vector.cpp:234:3:234:4 | ref arg v5 | vector.cpp:246:2:246:2 | v5 | | +| vector.cpp:234:13:234:14 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | +| vector.cpp:234:13:234:14 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | +| vector.cpp:234:13:234:14 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | +| vector.cpp:234:25:234:26 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | +| vector.cpp:234:25:234:26 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | +| vector.cpp:235:8:235:9 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | +| vector.cpp:235:11:235:15 | call to begin | vector.cpp:235:3:235:17 | ... = ... | | +| vector.cpp:235:11:235:15 | call to begin | vector.cpp:236:3:236:4 | i1 | | +| vector.cpp:235:11:235:15 | call to begin | vector.cpp:237:8:237:9 | i1 | | +| vector.cpp:235:11:235:15 | call to begin | vector.cpp:239:13:239:14 | i1 | | +| vector.cpp:235:11:235:15 | call to begin | vector.cpp:243:8:243:9 | i1 | | +| vector.cpp:236:3:236:4 | ref arg i1 | vector.cpp:237:8:237:9 | i1 | | +| vector.cpp:236:3:236:4 | ref arg i1 | vector.cpp:239:13:239:14 | i1 | | +| vector.cpp:236:3:236:4 | ref arg i1 | vector.cpp:243:8:243:9 | i1 | | +| vector.cpp:237:8:237:9 | i1 | vector.cpp:237:3:237:9 | ... = ... | | +| vector.cpp:237:8:237:9 | i1 | vector.cpp:238:3:238:4 | i2 | | +| vector.cpp:237:8:237:9 | i1 | vector.cpp:239:17:239:18 | i2 | | +| vector.cpp:237:8:237:9 | i1 | vector.cpp:244:8:244:9 | i2 | | +| vector.cpp:238:3:238:4 | ref arg i2 | vector.cpp:239:17:239:18 | i2 | | +| vector.cpp:238:3:238:4 | ref arg i2 | vector.cpp:244:8:244:9 | i2 | | +| vector.cpp:239:3:239:4 | ref arg v6 | vector.cpp:245:8:245:9 | v6 | | +| vector.cpp:239:3:239:4 | ref arg v6 | vector.cpp:246:2:246:2 | v6 | | +| vector.cpp:241:8:241:9 | ref arg v4 | vector.cpp:246:2:246:2 | v4 | | +| vector.cpp:242:8:242:9 | ref arg v5 | vector.cpp:246:2:246:2 | v5 | | +| vector.cpp:245:8:245:9 | ref arg v6 | vector.cpp:246:2:246:2 | v6 | | +| vector.cpp:252:19:252:20 | call to vector | vector.cpp:254:2:254:3 | v1 | | +| vector.cpp:252:19:252:20 | call to vector | vector.cpp:255:7:255:8 | v1 | | +| vector.cpp:252:19:252:20 | call to vector | vector.cpp:256:7:256:8 | v1 | | +| vector.cpp:252:19:252:20 | call to vector | vector.cpp:257:7:257:8 | v1 | | +| vector.cpp:252:19:252:20 | call to vector | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:252:23:252:24 | call to vector | vector.cpp:259:4:259:5 | v2 | | +| vector.cpp:252:23:252:24 | call to vector | vector.cpp:260:7:260:8 | v2 | | +| vector.cpp:252:23:252:24 | call to vector | vector.cpp:261:7:261:8 | v2 | | +| vector.cpp:252:23:252:24 | call to vector | vector.cpp:262:7:262:8 | v2 | | +| vector.cpp:252:23:252:24 | call to vector | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:255:7:255:8 | v1 | | +| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:256:7:256:8 | v1 | | +| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | +| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:254:15:254:20 | call to source | vector.cpp:254:2:254:3 | ref arg v1 | TAINT | +| vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:256:7:256:8 | v1 | | +| vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | +| vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | +| vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:257:7:257:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:257:10:257:13 | call to data | vector.cpp:257:7:257:18 | access to array | TAINT | +| vector.cpp:257:17:257:17 | 2 | vector.cpp:257:7:257:18 | access to array | TAINT | +| vector.cpp:259:2:259:13 | * ... [post update] | vector.cpp:259:7:259:10 | call to data [inner post update] | | +| vector.cpp:259:2:259:32 | ... = ... | vector.cpp:259:2:259:13 | * ... [post update] | | +| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:260:7:260:8 | v2 | | +| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | +| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | +| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:259:7:259:10 | call to data | vector.cpp:259:2:259:13 | * ... | TAINT | +| vector.cpp:259:17:259:30 | call to source | vector.cpp:259:2:259:32 | ... = ... | | +| vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | +| vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | +| vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | +| vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:262:7:262:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:262:10:262:13 | call to data | vector.cpp:262:7:262:18 | access to array | TAINT | +| vector.cpp:262:17:262:17 | 2 | vector.cpp:262:7:262:18 | access to array | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h index 46ac50fca8a..77df0e91f99 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h @@ -142,6 +142,8 @@ namespace std { vector& operator=(const vector& x); vector& operator=(vector&& x) noexcept/*(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value)*/; + template void assign(InputIterator first, InputIterator last); + void assign(size_type n, const T& u); iterator begin() noexcept; const_iterator begin() const noexcept; diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp index 8485479ad60..b36d6f36691 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp @@ -340,3 +340,12 @@ void test_string_at() sink(b); // tainted sink(c); // tainted } + +void test_string_data_more() +{ + std::string str("123"); + + str.data()[1] = ns_char::source(); + sink(str); // tainted [NOT DETECTED] + sink(str.data()); // tainted [NOT DETECTED] +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 86201c0be98..f96997714ec 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -237,3 +237,5 @@ | vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | | vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | +| vector.cpp:227:7:227:8 | v3 | vector.cpp:223:15:223:20 | call to source | +| vector.cpp:255:7:255:8 | v1 | vector.cpp:254:15:254:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 33da9c34694..f61eeb6adf1 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -173,3 +173,5 @@ | vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | | vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | +| vector.cpp:227:7:227:8 | vector.cpp:223:15:223:20 | AST only | +| vector.cpp:255:7:255:8 | vector.cpp:254:15:254:20 | AST only | 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 e6b0a905967..e271839aadd 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -5,9 +5,9 @@ using namespace std; int source(); -namespace ns_char +namespace ns_int { - char source(); + int source(); } void sink(int); @@ -87,7 +87,7 @@ void test_element_taint(int x) { { const std::vector &v8c = v8; std::vector::const_iterator it = v8c.begin(); - v8.insert(it, 10, ns_char::source()); + v8.insert(it, 10, ns_int::source()); } sink(v8); // tainted [NOT DETECTED] sink(v8.front()); // tainted [NOT DETECTED] @@ -212,3 +212,52 @@ void test_nested_vectors() sink(ff[0].vs[0]); // tainted [NOT DETECTED] } } + +void sink(std::vector::iterator &); + +void test_vector_assign() { + std::vector v1, v2, v3; + + v1.assign(100, 0); + v2.assign(100, ns_int::source()); + v3.push_back(source()); + + sink(v1); + sink(v2); // tainted [NOT DETECTED] + sink(v3); // tainted + + { + std::vector v4, v5, v6; + std::vector::iterator i1, i2; + + v4.assign(v1.begin(), v1.end()); + v5.assign(v3.begin(), v3.end()); + i1 = v3.begin(); + i1++; + i2 = i1; + i2++; + v6.assign(i1, i2); + + sink(v4); + sink(v5); // tainted [NOT DETECTED] + sink(i1); // tainted [NOT DETECTED] + sink(i2); // tainted [NOT DETECTED] + sink(v6); // tainted [NOT DETECTED] + } +} + +void sink(int *); + +void test_data_more() { + std::vector v1, v2; + + v1.push_back(source()); + sink(v1); // tainted + sink(v1.data()); // tainted [NOT DETECTED] + sink(v1.data()[2]); // tainted [NOT DETECTED] + + *(v2.data()) = ns_int::source(); + sink(v2); // tainted [NOT DETECTED] + sink(v2.data()); // tainted [NOT DETECTED] + sink(v2.data()[2]); // tainted [NOT DETECTED] +} From 6ae96baaf6940e7f02697febf505ffe3e5552a75 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 26 Aug 2020 14:48:10 +0100 Subject: [PATCH 114/146] C++: Model std::vector::data. --- .../cpp/models/implementations/StdContainer.qll | 13 +++++++++++++ .../dataflow/taint-tests/localTaint.expected | 7 +++++++ .../dataflow/taint-tests/taint.expected | 2 ++ .../dataflow/taint-tests/test_diff.expected | 2 ++ .../library-tests/dataflow/taint-tests/vector.cpp | 4 ++-- 5 files changed, 26 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 5325f411a0c..23669894b2e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -33,6 +33,19 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction { } } +/** + * The standard container function `data`. + */ +class StdSequenceContainerData extends TaintFunction { + StdSequenceContainerData() { this.hasQualifiedName("std", ["array", "vector"], "data") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from container itself (qualifier) to return value + input.isQualifierObject() and + output.isReturnValueDeref() + } +} + /** * The standard container functions `push_back` and `push_front`. */ 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 2f5179c15ed..94499bf7df3 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1864,6 +1864,7 @@ | vector.cpp:74:2:74:3 | ref arg v6 | vector.cpp:75:7:75:8 | v6 | | | vector.cpp:74:2:74:3 | ref arg v6 | vector.cpp:76:7:76:8 | v6 | | | vector.cpp:74:2:74:3 | ref arg v6 | vector.cpp:101:1:101:1 | v6 | | +| vector.cpp:74:2:74:3 | v6 | vector.cpp:74:5:74:8 | call to data | TAINT | | vector.cpp:74:2:74:13 | access to array [post update] | vector.cpp:74:5:74:8 | call to data [inner post update] | | | vector.cpp:74:2:74:24 | ... = ... | vector.cpp:74:2:74:13 | access to array [post update] | | | vector.cpp:74:5:74:8 | call to data | vector.cpp:74:2:74:13 | access to array | TAINT | @@ -1872,6 +1873,7 @@ | vector.cpp:75:7:75:8 | ref arg v6 | vector.cpp:76:7:76:8 | v6 | | | vector.cpp:75:7:75:8 | ref arg v6 | vector.cpp:101:1:101:1 | v6 | | | vector.cpp:76:7:76:8 | ref arg v6 | vector.cpp:101:1:101:1 | v6 | | +| vector.cpp:76:7:76:8 | v6 | vector.cpp:76:10:76:13 | call to data | TAINT | | vector.cpp:76:10:76:13 | call to data | vector.cpp:76:7:76:18 | access to array | TAINT | | vector.cpp:76:17:76:17 | 2 | vector.cpp:76:7:76:18 | access to array | TAINT | | vector.cpp:79:33:79:34 | v7 | vector.cpp:80:41:80:43 | v7c | | @@ -2317,7 +2319,9 @@ | vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | | vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | | vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:256:7:256:8 | v1 | vector.cpp:256:10:256:13 | call to data | TAINT | | vector.cpp:257:7:257:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | +| vector.cpp:257:7:257:8 | v1 | vector.cpp:257:10:257:13 | call to data | TAINT | | vector.cpp:257:10:257:13 | call to data | vector.cpp:257:7:257:18 | access to array | TAINT | | vector.cpp:257:17:257:17 | 2 | vector.cpp:257:7:257:18 | access to array | TAINT | | vector.cpp:259:2:259:13 | * ... [post update] | vector.cpp:259:7:259:10 | call to data [inner post update] | | @@ -2326,6 +2330,7 @@ | vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | | vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | | vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:259:4:259:5 | v2 | vector.cpp:259:7:259:10 | call to data | TAINT | | vector.cpp:259:7:259:10 | call to data | vector.cpp:259:2:259:13 | * ... | TAINT | | vector.cpp:259:17:259:30 | call to source | vector.cpp:259:2:259:32 | ... = ... | | | vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | @@ -2333,6 +2338,8 @@ | vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | | vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | | vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:261:7:261:8 | v2 | vector.cpp:261:10:261:13 | call to data | TAINT | | vector.cpp:262:7:262:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | +| vector.cpp:262:7:262:8 | v2 | vector.cpp:262:10:262:13 | call to data | TAINT | | vector.cpp:262:10:262:13 | call to data | vector.cpp:262:7:262:18 | access to array | TAINT | | vector.cpp:262:17:262:17 | 2 | vector.cpp:262:7:262:18 | access to array | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index f96997714ec..6d25dd43280 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -239,3 +239,5 @@ | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | | vector.cpp:227:7:227:8 | v3 | vector.cpp:223:15:223:20 | call to source | | vector.cpp:255:7:255:8 | v1 | vector.cpp:254:15:254:20 | call to source | +| vector.cpp:256:10:256:13 | call to data | vector.cpp:254:15:254:20 | call to source | +| vector.cpp:257:7:257:18 | access to array | vector.cpp:254:15:254:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index f61eeb6adf1..3f7ad193672 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -175,3 +175,5 @@ | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | | vector.cpp:227:7:227:8 | vector.cpp:223:15:223:20 | AST only | | vector.cpp:255:7:255:8 | vector.cpp:254:15:254:20 | AST only | +| vector.cpp:256:10:256:13 | vector.cpp:254:15:254:20 | AST only | +| vector.cpp:257:7:257:18 | vector.cpp:254:15:254:20 | AST only | 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 e271839aadd..990d360f60d 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -253,8 +253,8 @@ void test_data_more() { v1.push_back(source()); sink(v1); // tainted - sink(v1.data()); // tainted [NOT DETECTED] - sink(v1.data()[2]); // tainted [NOT DETECTED] + sink(v1.data()); // tainted + sink(v1.data()[2]); // tainted *(v2.data()) = ns_int::source(); sink(v2); // tainted [NOT DETECTED] From fbff44ea45ee2910cd7cc3637e8ecf0515bcbb8a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 26 Aug 2020 15:37:11 +0100 Subject: [PATCH 115/146] C++: Add reverse taint as well. --- .../code/cpp/models/implementations/StdContainer.qll | 5 +++++ .../dataflow/taint-tests/localTaint.expected | 4 ++++ .../library-tests/dataflow/taint-tests/taint.expected | 5 +++++ .../dataflow/taint-tests/test_diff.expected | 5 +++++ .../test/library-tests/dataflow/taint-tests/vector.cpp | 10 +++++----- 5 files changed, 24 insertions(+), 5 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 23669894b2e..b5ce32c3a4f 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -43,6 +43,11 @@ class StdSequenceContainerData extends TaintFunction { // flow from container itself (qualifier) to return value input.isQualifierObject() and output.isReturnValueDeref() + or + // reverse flow from returned reference to the qualifier (for writes to + // `data`) + input.isReturnValueDeref() and + output.isQualifierObject() } } 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 94499bf7df3..184eb126f2c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1868,6 +1868,7 @@ | vector.cpp:74:2:74:13 | access to array [post update] | vector.cpp:74:5:74:8 | call to data [inner post update] | | | vector.cpp:74:2:74:24 | ... = ... | vector.cpp:74:2:74:13 | access to array [post update] | | | vector.cpp:74:5:74:8 | call to data | vector.cpp:74:2:74:13 | access to array | TAINT | +| vector.cpp:74:5:74:8 | call to data [inner post update] | vector.cpp:74:2:74:3 | ref arg v6 | TAINT | | vector.cpp:74:12:74:12 | 2 | vector.cpp:74:2:74:13 | access to array | TAINT | | vector.cpp:74:17:74:22 | call to source | vector.cpp:74:2:74:24 | ... = ... | | | vector.cpp:75:7:75:8 | ref arg v6 | vector.cpp:76:7:76:8 | v6 | | @@ -2320,6 +2321,7 @@ | vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | | vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | | vector.cpp:256:7:256:8 | v1 | vector.cpp:256:10:256:13 | call to data | TAINT | +| vector.cpp:256:10:256:13 | ref arg call to data | vector.cpp:256:7:256:8 | ref arg v1 | TAINT | | vector.cpp:257:7:257:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | | vector.cpp:257:7:257:8 | v1 | vector.cpp:257:10:257:13 | call to data | TAINT | | vector.cpp:257:10:257:13 | call to data | vector.cpp:257:7:257:18 | access to array | TAINT | @@ -2332,6 +2334,7 @@ | vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | | vector.cpp:259:4:259:5 | v2 | vector.cpp:259:7:259:10 | call to data | TAINT | | vector.cpp:259:7:259:10 | call to data | vector.cpp:259:2:259:13 | * ... | TAINT | +| vector.cpp:259:7:259:10 | call to data [inner post update] | vector.cpp:259:4:259:5 | ref arg v2 | TAINT | | vector.cpp:259:17:259:30 | call to source | vector.cpp:259:2:259:32 | ... = ... | | | vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | | vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | @@ -2339,6 +2342,7 @@ | vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | | vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | | vector.cpp:261:7:261:8 | v2 | vector.cpp:261:10:261:13 | call to data | TAINT | +| vector.cpp:261:10:261:13 | ref arg call to data | vector.cpp:261:7:261:8 | ref arg v2 | TAINT | | vector.cpp:262:7:262:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | | vector.cpp:262:7:262:8 | v2 | vector.cpp:262:10:262:13 | call to data | TAINT | | vector.cpp:262:10:262:13 | call to data | vector.cpp:262:7:262:18 | access to array | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 6d25dd43280..4f1ad165980 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -218,6 +218,8 @@ | vector.cpp:70:7:70:8 | v5 | vector.cpp:69:15:69:20 | call to source | | vector.cpp:71:10:71:14 | call to front | vector.cpp:69:15:69:20 | call to source | | vector.cpp:72:10:72:13 | call to back | vector.cpp:69:15:69:20 | call to source | +| vector.cpp:75:7:75:8 | v6 | vector.cpp:74:17:74:22 | call to source | +| vector.cpp:76:7:76:18 | access to array | vector.cpp:74:17:74:22 | call to source | | vector.cpp:97:7:97:8 | v9 | vector.cpp:96:13:96:18 | call to source | | vector.cpp:98:10:98:11 | call to at | vector.cpp:96:13:96:18 | call to source | | vector.cpp:99:10:99:11 | call to at | vector.cpp:96:13:96:18 | call to source | @@ -241,3 +243,6 @@ | vector.cpp:255:7:255:8 | v1 | vector.cpp:254:15:254:20 | call to source | | vector.cpp:256:10:256:13 | call to data | vector.cpp:254:15:254:20 | call to source | | vector.cpp:257:7:257:18 | access to array | vector.cpp:254:15:254:20 | call to source | +| vector.cpp:260:7:260:8 | v2 | vector.cpp:259:17:259:30 | call to source | +| vector.cpp:261:10:261:13 | call to data | vector.cpp:259:17:259:30 | call to source | +| vector.cpp:262:7:262:18 | access to array | vector.cpp:259:17:259:30 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 3f7ad193672..a612bbfabd8 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -153,6 +153,8 @@ | vector.cpp:70:7:70:8 | vector.cpp:69:15:69:20 | AST only | | vector.cpp:71:10:71:14 | vector.cpp:69:15:69:20 | AST only | | vector.cpp:72:10:72:13 | vector.cpp:69:15:69:20 | AST only | +| vector.cpp:75:7:75:8 | vector.cpp:74:17:74:22 | AST only | +| vector.cpp:76:7:76:18 | vector.cpp:74:17:74:22 | AST only | | vector.cpp:97:7:97:8 | vector.cpp:96:13:96:18 | AST only | | vector.cpp:98:10:98:11 | vector.cpp:96:13:96:18 | AST only | | vector.cpp:99:10:99:11 | vector.cpp:96:13:96:18 | AST only | @@ -177,3 +179,6 @@ | vector.cpp:255:7:255:8 | vector.cpp:254:15:254:20 | AST only | | vector.cpp:256:10:256:13 | vector.cpp:254:15:254:20 | AST only | | vector.cpp:257:7:257:18 | vector.cpp:254:15:254:20 | AST only | +| vector.cpp:260:7:260:8 | vector.cpp:259:17:259:30 | AST only | +| vector.cpp:261:10:261:13 | vector.cpp:259:17:259:30 | AST only | +| vector.cpp:262:7:262:18 | vector.cpp:259:17:259:30 | AST only | 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 990d360f60d..b1b65062294 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -72,8 +72,8 @@ void test_element_taint(int x) { sink(v5.back()); // tainted v6.data()[2] = source(); - sink(v6); // tainted [NOT DETECTED] - sink(v6.data()[2]); // tainted [NOT DETECTED] + sink(v6); // tainted + sink(v6.data()[2]); // tainted { const std::vector &v7c = v7; // (workaround because our iterators don't convert to const_iterator) @@ -257,7 +257,7 @@ void test_data_more() { sink(v1.data()[2]); // tainted *(v2.data()) = ns_int::source(); - sink(v2); // tainted [NOT DETECTED] - sink(v2.data()); // tainted [NOT DETECTED] - sink(v2.data()[2]); // tainted [NOT DETECTED] + sink(v2); // tainted + sink(v2.data()); // tainted + sink(v2.data()[2]); // tainted } From fbac4ce44f5313bd3341837a048f2d36d7524b64 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 26 Aug 2020 18:10:15 +0100 Subject: [PATCH 116/146] C++: Split StdStringCStr and allow reverse flow on data. --- .../cpp/models/implementations/StdString.qll | 22 +++++++++++++++++-- .../dataflow/taint-tests/localTaint.expected | 1 + .../dataflow/taint-tests/string.cpp | 4 ++-- .../dataflow/taint-tests/taint.expected | 2 ++ .../dataflow/taint-tests/test_diff.expected | 2 ++ 5 files changed, 27 insertions(+), 4 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 5261285cf3c..880b7db981b 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -8,10 +8,10 @@ class StdBasicString extends TemplateClass { } /** - * The `std::string` functions `c_str` and `data`. + * The `std::string` function `c_str`. */ class StdStringCStr extends TaintFunction { - StdStringCStr() { this.hasQualifiedName("std", "basic_string", ["c_str", "data"]) } + StdStringCStr() { this.hasQualifiedName("std", "basic_string", "c_str") } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value @@ -20,6 +20,24 @@ class StdStringCStr extends TaintFunction { } } +/** + * The `std::string` function `data`. + */ +class StdStringData extends TaintFunction { + StdStringData() { this.hasQualifiedName("std", "basic_string", "data") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from string itself (qualifier) to return value + input.isQualifierObject() and + output.isReturnValue() + or + // reverse flow from returned reference to the qualifier (for writes to + // `data`) + input.isReturnValueDeref() and + output.isQualifierObject() + } +} + /** * The `std::string` function `operator+`. */ 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 184eb126f2c..d3382de9ea3 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -727,6 +727,7 @@ | string.cpp:348:2:348:14 | access to array [post update] | string.cpp:348:6:348:9 | call to data [inner post update] | | | string.cpp:348:2:348:34 | ... = ... | string.cpp:348:2:348:14 | access to array [post update] | | | string.cpp:348:6:348:9 | call to data | string.cpp:348:2:348:14 | access to array | TAINT | +| string.cpp:348:6:348:9 | call to data [inner post update] | string.cpp:348:2:348:4 | ref arg str | TAINT | | string.cpp:348:13:348:13 | 1 | string.cpp:348:2:348:14 | access to array | TAINT | | string.cpp:348:18:348:32 | call to source | string.cpp:348:2:348:34 | ... = ... | | | string.cpp:350:7:350:9 | str | string.cpp:350:11:350:14 | call to data | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp index b36d6f36691..118a4bcd1a9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/string.cpp @@ -346,6 +346,6 @@ void test_string_data_more() std::string str("123"); str.data()[1] = ns_char::source(); - sink(str); // tainted [NOT DETECTED] - sink(str.data()); // tainted [NOT DETECTED] + sink(str); // tainted + sink(str.data()); // tainted } diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 4f1ad165980..60f25289d07 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -94,6 +94,8 @@ | string.cpp:339:7:339:7 | a | string.cpp:335:9:335:23 | call to source | | string.cpp:340:7:340:7 | b | string.cpp:336:12:336:26 | call to source | | string.cpp:341:7:341:7 | c | string.cpp:335:9:335:23 | call to source | +| string.cpp:349:7:349:9 | str | string.cpp:348:18:348:32 | call to source | +| string.cpp:350:11:350:14 | call to data | string.cpp:348:18:348:32 | call to source | | structlikeclass.cpp:35:8:35:9 | s1 | structlikeclass.cpp:29:22:29:27 | call to source | | structlikeclass.cpp:36:8:36:9 | s2 | structlikeclass.cpp:30:24:30:29 | call to source | | structlikeclass.cpp:37:8:37:9 | s3 | structlikeclass.cpp:29:22:29:27 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index a612bbfabd8..b39d64ea90e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -91,6 +91,8 @@ | string.cpp:339:7:339:7 | string.cpp:335:9:335:23 | AST only | | string.cpp:340:7:340:7 | string.cpp:336:12:336:26 | AST only | | string.cpp:341:7:341:7 | string.cpp:335:9:335:23 | AST only | +| string.cpp:349:7:349:9 | string.cpp:348:18:348:32 | AST only | +| string.cpp:350:11:350:14 | string.cpp:348:18:348:32 | AST only | | structlikeclass.cpp:35:8:35:9 | structlikeclass.cpp:29:22:29:27 | AST only | | structlikeclass.cpp:36:8:36:9 | structlikeclass.cpp:30:24:30:29 | AST only | | structlikeclass.cpp:37:8:37:9 | structlikeclass.cpp:29:22:29:27 | AST only | From 0952fb9777da98702093b6c915f418ea58bb92e7 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 26 Aug 2020 18:32:46 +0100 Subject: [PATCH 117/146] C++: Minor correction in one of the string models. --- .../src/semmle/code/cpp/models/implementations/StdString.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 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 880b7db981b..7ed73e59a21 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -16,7 +16,7 @@ class StdStringCStr extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value input.isQualifierObject() and - output.isReturnValue() + output.isReturnValueDeref() } } @@ -29,7 +29,7 @@ class StdStringData extends TaintFunction { override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string itself (qualifier) to return value input.isQualifierObject() and - output.isReturnValue() + output.isReturnValueDeref() or // reverse flow from returned reference to the qualifier (for writes to // `data`) From 569e54e7bb43a242548e1a67d23119d5186fc4db Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 27 Aug 2020 11:19:55 +0200 Subject: [PATCH 118/146] Python: Remove symlink from experimental test --- .../experimental/library-tests/CallGraph-xfail/CallGraphTest.qll | 1 - .../test/experimental/library-tests/CallGraph-xfail/PointsTo.ql | 1 - .../experimental/library-tests/CallGraph-xfail/PointsTo.qlref | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) delete mode 120000 python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll delete mode 120000 python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql create mode 100644 python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.qlref diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll b/python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll deleted file mode 120000 index 3651467c330..00000000000 --- a/python/ql/test/experimental/library-tests/CallGraph-xfail/CallGraphTest.qll +++ /dev/null @@ -1 +0,0 @@ -../CallGraph/CallGraphTest.qll \ No newline at end of file diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql deleted file mode 120000 index cdea4e77ced..00000000000 --- a/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.ql +++ /dev/null @@ -1 +0,0 @@ -../CallGraph/PointsTo.ql \ No newline at end of file diff --git a/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.qlref b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.qlref new file mode 100644 index 00000000000..da8a0d1631a --- /dev/null +++ b/python/ql/test/experimental/library-tests/CallGraph-xfail/PointsTo.qlref @@ -0,0 +1 @@ +../CallGraph/PointsTo.ql From 111da4c35203f170f20e60c5f8030c7f79fc08f8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 26 Aug 2020 18:42:24 +0100 Subject: [PATCH 119/146] C++: Add a model of std::vector::assign. --- .../models/implementations/StdContainer.qll | 26 +++++++++++++++++++ .../dataflow/taint-tests/localTaint.expected | 4 +++ .../dataflow/taint-tests/taint.expected | 1 + .../dataflow/taint-tests/test_diff.expected | 1 + .../dataflow/taint-tests/vector.cpp | 2 +- 5 files changed, 33 insertions(+), 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 b5ce32c3a4f..bee2ab4974c 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -88,6 +88,32 @@ class StdSequenceContainerFrontBack extends TaintFunction { } } +/** + * The standard container function `assign`. + */ +class StdSequenceContainerAssign extends TaintFunction { + StdSequenceContainerAssign() { + this.hasQualifiedName("std", ["vector", "deque", "list", "forward_list"], "assign") + } + + /** + * Gets the index of a parameter to this function that is a reference to the + * value type of the container. + */ + int getAValueTypeParameterIndex() { + getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0) // i.e. the `T` of this `std::vector` + or + getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = + getDeclaringType().getTemplateArgument(0) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + // flow from parameter to string itself (qualifier) and return value + input.isParameterDeref(getAValueTypeParameterIndex()) and + output.isQualifierObject() + } +} + /** * The standard container `swap` functions. */ 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 d3382de9ea3..ee5b8deddcb 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -2244,8 +2244,12 @@ | vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:233:13:233:14 | v1 | | | vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | | vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | +| vector.cpp:221:12:221:14 | 100 | vector.cpp:221:2:221:3 | ref arg v1 | TAINT | +| vector.cpp:221:17:221:17 | 0 | vector.cpp:221:2:221:3 | ref arg v1 | TAINT | | vector.cpp:222:2:222:3 | ref arg v2 | vector.cpp:226:7:226:8 | v2 | | | vector.cpp:222:2:222:3 | ref arg v2 | vector.cpp:247:1:247:1 | v2 | | +| vector.cpp:222:12:222:14 | 100 | vector.cpp:222:2:222:3 | ref arg v2 | TAINT | +| vector.cpp:222:17:222:30 | call to source | vector.cpp:222:2:222:3 | ref arg v2 | TAINT | | vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:227:7:227:8 | v3 | | | vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:234:13:234:14 | v3 | | | vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 60f25289d07..daaadcfe6f1 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -241,6 +241,7 @@ | vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | | vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | +| vector.cpp:226:7:226:8 | v2 | vector.cpp:222:17:222:30 | call to source | | vector.cpp:227:7:227:8 | v3 | vector.cpp:223:15:223:20 | call to source | | vector.cpp:255:7:255:8 | v1 | vector.cpp:254:15:254:20 | call to source | | vector.cpp:256:10:256:13 | call to data | vector.cpp:254:15:254:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index b39d64ea90e..eb5167415cb 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -177,6 +177,7 @@ | vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | | vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | +| vector.cpp:226:7:226:8 | vector.cpp:222:17:222:30 | AST only | | vector.cpp:227:7:227:8 | vector.cpp:223:15:223:20 | AST only | | vector.cpp:255:7:255:8 | vector.cpp:254:15:254:20 | AST only | | vector.cpp:256:10:256:13 | vector.cpp:254:15:254:20 | AST only | 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 b1b65062294..4f2c3168269 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -223,7 +223,7 @@ void test_vector_assign() { v3.push_back(source()); sink(v1); - sink(v2); // tainted [NOT DETECTED] + sink(v2); // tainted sink(v3); // tainted { From 909bff231362c51896bb828ae1528b7b592ae3d0 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 27 Aug 2020 11:48:56 +0200 Subject: [PATCH 120/146] Python: Make import of python private in shared dataflow --- python/ql/src/experimental/dataflow/DataFlow.qll | 2 +- python/ql/src/experimental/dataflow/DataFlow2.qll | 2 +- python/ql/src/experimental/dataflow/TaintTracking.qll | 2 +- python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/ql/src/experimental/dataflow/DataFlow.qll b/python/ql/src/experimental/dataflow/DataFlow.qll index 7f1c2c0c4e5..74c775917d7 100644 --- a/python/ql/src/experimental/dataflow/DataFlow.qll +++ b/python/ql/src/experimental/dataflow/DataFlow.qll @@ -15,7 +15,7 @@ * `DataFlow::localFlowStep` with arguments of type `DataFlow::Node`. */ -import python +private import python /** * Provides classes for performing local (intra-procedural) and diff --git a/python/ql/src/experimental/dataflow/DataFlow2.qll b/python/ql/src/experimental/dataflow/DataFlow2.qll index cb4d8b60d1e..2e6f4412172 100644 --- a/python/ql/src/experimental/dataflow/DataFlow2.qll +++ b/python/ql/src/experimental/dataflow/DataFlow2.qll @@ -15,7 +15,7 @@ * `DataFlow::localFlowStep` with arguments of type `DataFlow::Node`. */ -import python +private import python /** * Provides classes for performing local (intra-procedural) and diff --git a/python/ql/src/experimental/dataflow/TaintTracking.qll b/python/ql/src/experimental/dataflow/TaintTracking.qll index c74684803ad..23c5111f3dd 100644 --- a/python/ql/src/experimental/dataflow/TaintTracking.qll +++ b/python/ql/src/experimental/dataflow/TaintTracking.qll @@ -8,7 +8,7 @@ * `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`. */ -import python +private import python /** * Provides classes for performing local (intra-procedural) and diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index 0c5db9f886d..7529fae63f4 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -2,7 +2,7 @@ * Provides Python-specific definitions for use in the data flow library. */ -import python +private import python private import DataFlowPrivate /** From 6f62803e1f79d608285a1ec9e0afb5702de257cd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 25 Aug 2020 15:27:40 +0100 Subject: [PATCH 121/146] C++: Taint tests for array and reference assignments. --- .../dataflow/taint-tests/arrayassignment.cpp | 147 ++++++++++++++++++ .../dataflow/taint-tests/localTaint.expected | 124 +++++++++++++++ .../dataflow/taint-tests/taint.expected | 5 + .../dataflow/taint-tests/test_diff.expected | 18 +++ .../dataflow/taint-tests/test_ir.expected | 19 +++ 5 files changed, 313 insertions(+) create mode 100644 cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp new file mode 100644 index 00000000000..c6a174249e3 --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/arrayassignment.cpp @@ -0,0 +1,147 @@ + +int source(); +void sink(int); +void sink(class MyInt); +void sink(class MyArray); + +void test_pointer_deref_assignment() +{ + int x = 0; + int *p_x = &x; + int *p2_x = &x; + int &r_x = x; + + *p_x = source(); + + sink(x); // tainted [DETECTED BY IR ONLY] + sink(*p_x); // tainted [DETECTED BY IR ONLY] + sink(*p2_x); // tainted [DETECTED BY IR ONLY] + sink(r_x); // tainted [DETECTED BY IR ONLY] +} + +void test_reference_deref_assignment() +{ + int x = 0; + int *p_x = &x; + int &r_x = x; + int &r2_x = x; + + r_x = source(); + + sink(x); // tainted [DETECTED BY IR ONLY] + sink(*p_x); // tainted [DETECTED BY IR ONLY] + sink(r_x); // tainted + sink(r2_x); // tainted [DETECTED BY IR ONLY] +} + +class MyInt +{ +public: + MyInt() : i(0) {} + + int &get() { return i; } + + MyInt &operator=(const int &other); + MyInt &operator=(const MyInt &other); + + int i; +}; + +void test_myint_member_assignment() +{ + MyInt mi; + + mi.i = source(); + + sink(mi); // tainted [DETECTED BY IR ONLY] + sink(mi.get()); // tainted +} + +void test_myint_method_assignment() +{ + MyInt mi; + + mi.get() = source(); + + sink(mi); // tainted [DETECTED BY IR ONLY] + sink(mi.get()); // tainted +} + +void test_myint_overloaded_assignment() +{ + MyInt mi, mi2; + + mi = source(); + mi2 = mi; + + sink(mi); // tainted [NOT DETECTED] + sink(mi.get()); // tainted [NOT DETECTED] + sink(mi2); // tainted [NOT DETECTED] + sink(mi2.get()); // tainted [NOT DETECTED] +} + +class MyArray +{ +public: + MyArray() : values({0}) {} + + int &get(int i) { return values[i]; } + + int &operator[](int i); + + int values[10]; +}; + +void test_myarray_member_assignment() +{ + MyArray ma; + + ma.values[0] = source(); + + sink(ma.values[0]); // tainted +} + +void test_myarray_method_assignment() +{ + MyArray ma; + + ma.get(0) = source(); + + sink(ma.get(0)); // tainted [NOT DETECTED] +} + +void test_myarray_overloaded_assignment() +{ + MyArray ma, ma2; + + ma[0] = source(); + ma2 = ma; + + sink(ma[0]); // tainted [NOT DETECTED] + sink(ma2[0]); // tainted [NOT DETECTED] +} + +void sink(int *); + +void test_array_reference_assignment() +{ + int arr1[10] = {0}; + int arr2[10] = {0}; + int arr3[10] = {0}; + int &ref1 = arr1[5]; + int *ptr2, *ptr3; + + ref1 = source(); + sink(ref1); // tainted + sink(arr1[5]); // tainted [DETECTED BY IR ONLY] + + ptr2 = &(arr2[5]); + *ptr2 = source(); + sink(*ptr2); // tainted [DETECTED BY IR ONLY] + sink(arr2[5]); // tainted [DETECTED BY IR ONLY] + + ptr3 = arr3; + ptr3[5] = source(); + sink(ptr3[5]); // tainted [DETECTED BY IR ONLY] + sink(arr3[5]); // tainted [DETECTED BY IR ONLY] +} 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 df455e9bdaa..2eb8ba047c9 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -1,3 +1,127 @@ +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:10:14:10:14 | x | | +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:11:15:11:15 | x | | +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:12:13:12:13 | x | | +| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:16:7:16:7 | x | | +| arrayassignment.cpp:10:13:10:14 | & ... | arrayassignment.cpp:14:3:14:5 | p_x | | +| arrayassignment.cpp:10:13:10:14 | & ... | arrayassignment.cpp:17:8:17:10 | p_x | | +| arrayassignment.cpp:10:14:10:14 | x | arrayassignment.cpp:10:13:10:14 | & ... | | +| arrayassignment.cpp:11:14:11:15 | & ... | arrayassignment.cpp:18:8:18:11 | p2_x | | +| arrayassignment.cpp:11:15:11:15 | x | arrayassignment.cpp:11:14:11:15 | & ... | | +| arrayassignment.cpp:12:13:12:13 | x | arrayassignment.cpp:19:7:19:9 | r_x | | +| arrayassignment.cpp:14:3:14:5 | p_x | arrayassignment.cpp:14:2:14:5 | * ... | TAINT | +| arrayassignment.cpp:14:9:14:14 | call to source | arrayassignment.cpp:14:2:14:16 | ... = ... | | +| arrayassignment.cpp:17:8:17:10 | p_x | arrayassignment.cpp:17:7:17:10 | * ... | TAINT | +| arrayassignment.cpp:18:8:18:11 | p2_x | arrayassignment.cpp:18:7:18:11 | * ... | TAINT | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:25:14:25:14 | x | | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:26:13:26:13 | x | | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:27:14:27:14 | x | | +| arrayassignment.cpp:24:9:24:10 | 0 | arrayassignment.cpp:31:7:31:7 | x | | +| arrayassignment.cpp:25:13:25:14 | & ... | arrayassignment.cpp:32:8:32:10 | p_x | | +| arrayassignment.cpp:25:14:25:14 | x | arrayassignment.cpp:25:13:25:14 | & ... | | +| arrayassignment.cpp:27:14:27:14 | x | arrayassignment.cpp:34:7:34:10 | r2_x | | +| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:29:2:29:15 | ... = ... | | +| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:33:7:33:9 | r_x | | +| arrayassignment.cpp:32:8:32:10 | p_x | arrayassignment.cpp:32:7:32:10 | * ... | TAINT | +| arrayassignment.cpp:37:7:37:7 | Unknown literal | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT | +| arrayassignment.cpp:37:7:37:7 | this | arrayassignment.cpp:37:7:37:7 | constructor init of field i [pre-this] | | +| arrayassignment.cpp:40:2:40:6 | this | arrayassignment.cpp:40:12:40:15 | constructor init of field i [pre-this] | | +| arrayassignment.cpp:40:12:40:15 | 0 | arrayassignment.cpp:40:12:40:15 | constructor init of field i | TAINT | +| arrayassignment.cpp:42:7:42:9 | this | arrayassignment.cpp:42:22:42:22 | this | | +| arrayassignment.cpp:52:8:52:9 | call to MyInt | arrayassignment.cpp:54:2:54:3 | mi | | +| arrayassignment.cpp:52:8:52:9 | call to MyInt | arrayassignment.cpp:56:7:56:8 | mi | | +| arrayassignment.cpp:52:8:52:9 | call to MyInt | arrayassignment.cpp:57:7:57:8 | mi | | +| arrayassignment.cpp:54:2:54:3 | mi [post update] | arrayassignment.cpp:56:7:56:8 | mi | | +| arrayassignment.cpp:54:2:54:3 | mi [post update] | arrayassignment.cpp:57:7:57:8 | mi | | +| arrayassignment.cpp:54:2:54:16 | ... = ... | arrayassignment.cpp:54:5:54:5 | i [post update] | | +| arrayassignment.cpp:54:9:54:14 | call to source | arrayassignment.cpp:54:2:54:16 | ... = ... | | +| arrayassignment.cpp:62:8:62:9 | call to MyInt | arrayassignment.cpp:64:2:64:3 | mi | | +| arrayassignment.cpp:62:8:62:9 | call to MyInt | arrayassignment.cpp:66:7:66:8 | mi | | +| arrayassignment.cpp:62:8:62:9 | call to MyInt | arrayassignment.cpp:67:7:67:8 | mi | | +| arrayassignment.cpp:64:2:64:3 | ref arg mi | arrayassignment.cpp:66:7:66:8 | mi | | +| arrayassignment.cpp:64:2:64:3 | ref arg mi | arrayassignment.cpp:67:7:67:8 | mi | | +| arrayassignment.cpp:64:2:64:20 | ... = ... | arrayassignment.cpp:64:5:64:7 | call to get [post update] | | +| arrayassignment.cpp:64:13:64:18 | call to source | arrayassignment.cpp:64:2:64:20 | ... = ... | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:74:2:74:3 | mi | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:75:8:75:9 | mi | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:77:7:77:8 | mi | | +| arrayassignment.cpp:72:8:72:9 | call to MyInt | arrayassignment.cpp:78:7:78:8 | mi | | +| arrayassignment.cpp:72:12:72:14 | call to MyInt | arrayassignment.cpp:75:2:75:4 | mi2 | | +| arrayassignment.cpp:72:12:72:14 | call to MyInt | arrayassignment.cpp:79:7:79:9 | mi2 | | +| arrayassignment.cpp:72:12:72:14 | call to MyInt | arrayassignment.cpp:80:7:80:9 | mi2 | | +| arrayassignment.cpp:74:2:74:3 | ref arg mi | arrayassignment.cpp:75:8:75:9 | mi | | +| arrayassignment.cpp:74:2:74:3 | ref arg mi | arrayassignment.cpp:77:7:77:8 | mi | | +| arrayassignment.cpp:74:2:74:3 | ref arg mi | arrayassignment.cpp:78:7:78:8 | mi | | +| arrayassignment.cpp:75:2:75:4 | ref arg mi2 | arrayassignment.cpp:79:7:79:9 | mi2 | | +| arrayassignment.cpp:75:2:75:4 | ref arg mi2 | arrayassignment.cpp:80:7:80:9 | mi2 | | +| arrayassignment.cpp:75:8:75:9 | mi | arrayassignment.cpp:75:2:75:4 | ref arg mi2 | TAINT | +| arrayassignment.cpp:75:8:75:9 | mi | arrayassignment.cpp:75:6:75:6 | call to operator= | TAINT | +| arrayassignment.cpp:86:2:86:8 | this | arrayassignment.cpp:86:14:86:24 | constructor init of field values [pre-this] | | +| arrayassignment.cpp:86:14:86:24 | {...} | arrayassignment.cpp:86:14:86:24 | constructor init of field values | TAINT | +| arrayassignment.cpp:86:22:86:22 | 0 | arrayassignment.cpp:86:14:86:24 | {...} | TAINT | +| arrayassignment.cpp:88:7:88:9 | this | arrayassignment.cpp:88:27:88:32 | this | | +| arrayassignment.cpp:88:15:88:15 | i | arrayassignment.cpp:88:34:88:34 | i | | +| arrayassignment.cpp:88:27:88:32 | values | arrayassignment.cpp:88:27:88:35 | access to array | TAINT | +| arrayassignment.cpp:88:34:88:34 | i | arrayassignment.cpp:88:27:88:35 | access to array | TAINT | +| arrayassignment.cpp:97:10:97:11 | call to MyArray | arrayassignment.cpp:99:2:99:3 | ma | | +| arrayassignment.cpp:97:10:97:11 | call to MyArray | arrayassignment.cpp:101:7:101:8 | ma | | +| arrayassignment.cpp:99:2:99:3 | ma [post update] | arrayassignment.cpp:101:7:101:8 | ma | | +| arrayassignment.cpp:99:2:99:13 | access to array [post update] | arrayassignment.cpp:99:5:99:10 | values [inner post update] | | +| arrayassignment.cpp:99:2:99:24 | ... = ... | arrayassignment.cpp:99:2:99:13 | access to array [post update] | | +| arrayassignment.cpp:99:5:99:10 | values | arrayassignment.cpp:99:2:99:13 | access to array | TAINT | +| arrayassignment.cpp:99:12:99:12 | 0 | arrayassignment.cpp:99:2:99:13 | access to array | TAINT | +| arrayassignment.cpp:99:17:99:22 | call to source | arrayassignment.cpp:99:2:99:24 | ... = ... | | +| arrayassignment.cpp:101:10:101:15 | values | arrayassignment.cpp:101:7:101:18 | access to array | TAINT | +| arrayassignment.cpp:101:17:101:17 | 0 | arrayassignment.cpp:101:7:101:18 | access to array | TAINT | +| arrayassignment.cpp:106:10:106:11 | call to MyArray | arrayassignment.cpp:108:2:108:3 | ma | | +| arrayassignment.cpp:106:10:106:11 | call to MyArray | arrayassignment.cpp:110:7:110:8 | ma | | +| arrayassignment.cpp:108:2:108:3 | ref arg ma | arrayassignment.cpp:110:7:110:8 | ma | | +| arrayassignment.cpp:108:2:108:21 | ... = ... | arrayassignment.cpp:108:5:108:7 | call to get [post update] | | +| arrayassignment.cpp:108:14:108:19 | call to source | arrayassignment.cpp:108:2:108:21 | ... = ... | | +| arrayassignment.cpp:115:10:115:11 | call to MyArray | arrayassignment.cpp:117:2:117:3 | ma | | +| arrayassignment.cpp:115:10:115:11 | call to MyArray | arrayassignment.cpp:118:8:118:9 | ma | | +| arrayassignment.cpp:115:10:115:11 | call to MyArray | arrayassignment.cpp:120:7:120:8 | ma | | +| arrayassignment.cpp:117:2:117:3 | ref arg ma | arrayassignment.cpp:118:8:118:9 | ma | | +| arrayassignment.cpp:117:2:117:3 | ref arg ma | arrayassignment.cpp:120:7:120:8 | ma | | +| arrayassignment.cpp:117:2:117:17 | ... = ... | arrayassignment.cpp:117:4:117:4 | call to operator[] [post update] | | +| arrayassignment.cpp:117:10:117:15 | call to source | arrayassignment.cpp:117:2:117:17 | ... = ... | | +| arrayassignment.cpp:118:8:118:9 | ma | arrayassignment.cpp:118:2:118:9 | ... = ... | | +| arrayassignment.cpp:118:8:118:9 | ma | arrayassignment.cpp:121:7:121:9 | ma2 | | +| arrayassignment.cpp:128:16:128:19 | {...} | arrayassignment.cpp:131:14:131:17 | arr1 | | +| arrayassignment.cpp:128:16:128:19 | {...} | arrayassignment.cpp:136:7:136:10 | arr1 | | +| arrayassignment.cpp:128:18:128:18 | 0 | arrayassignment.cpp:128:16:128:19 | {...} | TAINT | +| arrayassignment.cpp:129:16:129:19 | {...} | arrayassignment.cpp:138:11:138:14 | arr2 | | +| arrayassignment.cpp:129:16:129:19 | {...} | arrayassignment.cpp:141:7:141:10 | arr2 | | +| arrayassignment.cpp:129:18:129:18 | 0 | arrayassignment.cpp:129:16:129:19 | {...} | TAINT | +| arrayassignment.cpp:130:16:130:19 | {...} | arrayassignment.cpp:143:9:143:12 | arr3 | | +| arrayassignment.cpp:130:16:130:19 | {...} | arrayassignment.cpp:146:7:146:10 | arr3 | | +| arrayassignment.cpp:130:18:130:18 | 0 | arrayassignment.cpp:130:16:130:19 | {...} | TAINT | +| arrayassignment.cpp:131:14:131:17 | arr1 | arrayassignment.cpp:131:14:131:20 | access to array | TAINT | +| arrayassignment.cpp:131:19:131:19 | 5 | arrayassignment.cpp:131:14:131:20 | access to array | TAINT | +| arrayassignment.cpp:134:9:134:14 | call to source | arrayassignment.cpp:134:2:134:16 | ... = ... | | +| arrayassignment.cpp:134:9:134:14 | call to source | arrayassignment.cpp:135:7:135:10 | ref1 | | +| arrayassignment.cpp:136:7:136:10 | arr1 | arrayassignment.cpp:136:7:136:13 | access to array | TAINT | +| arrayassignment.cpp:136:12:136:12 | 5 | arrayassignment.cpp:136:7:136:13 | access to array | TAINT | +| arrayassignment.cpp:138:9:138:18 | & ... | arrayassignment.cpp:138:2:138:18 | ... = ... | | +| arrayassignment.cpp:138:9:138:18 | & ... | arrayassignment.cpp:139:3:139:6 | ptr2 | | +| arrayassignment.cpp:138:9:138:18 | & ... | arrayassignment.cpp:140:8:140:11 | ptr2 | | +| arrayassignment.cpp:138:11:138:14 | arr2 | arrayassignment.cpp:138:11:138:17 | access to array | TAINT | +| arrayassignment.cpp:138:11:138:17 | access to array | arrayassignment.cpp:138:9:138:18 | & ... | | +| arrayassignment.cpp:138:16:138:16 | 5 | arrayassignment.cpp:138:11:138:17 | access to array | TAINT | +| arrayassignment.cpp:139:3:139:6 | ptr2 | arrayassignment.cpp:139:2:139:6 | * ... | TAINT | +| arrayassignment.cpp:139:10:139:15 | call to source | arrayassignment.cpp:139:2:139:17 | ... = ... | | +| arrayassignment.cpp:140:8:140:11 | ptr2 | arrayassignment.cpp:140:7:140:11 | * ... | TAINT | +| arrayassignment.cpp:141:7:141:10 | arr2 | arrayassignment.cpp:141:7:141:13 | access to array | TAINT | +| arrayassignment.cpp:141:12:141:12 | 5 | arrayassignment.cpp:141:7:141:13 | access to array | TAINT | +| arrayassignment.cpp:143:9:143:12 | arr3 | arrayassignment.cpp:143:2:143:12 | ... = ... | | +| arrayassignment.cpp:143:9:143:12 | arr3 | arrayassignment.cpp:144:2:144:5 | ptr3 | | +| arrayassignment.cpp:143:9:143:12 | arr3 | arrayassignment.cpp:145:7:145:10 | ptr3 | | +| arrayassignment.cpp:144:2:144:5 | ptr3 | arrayassignment.cpp:144:2:144:8 | access to array | TAINT | +| arrayassignment.cpp:144:7:144:7 | 5 | arrayassignment.cpp:144:2:144:8 | access to array | TAINT | +| arrayassignment.cpp:144:12:144:17 | call to source | arrayassignment.cpp:144:2:144:19 | ... = ... | | +| arrayassignment.cpp:145:7:145:10 | ptr3 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT | +| arrayassignment.cpp:145:12:145:12 | 5 | arrayassignment.cpp:145:7:145:13 | access to array | TAINT | +| arrayassignment.cpp:146:7:146:10 | arr3 | arrayassignment.cpp:146:7:146:13 | access to array | TAINT | +| arrayassignment.cpp:146:12:146:12 | 5 | arrayassignment.cpp:146:7:146:13 | access to array | TAINT | | copyableclass.cpp:8:2:8:16 | this | copyableclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | | | copyableclass.cpp:8:22:8:23 | _v | copyableclass.cpp:8:30:8:31 | _v | | | copyableclass.cpp:8:30:8:31 | _v | copyableclass.cpp:8:28:8:32 | constructor init of field v | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index 86201c0be98..4ef371b83d8 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -1,3 +1,8 @@ +| arrayassignment.cpp:33:7:33:9 | r_x | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:57:10:57:12 | call to get | arrayassignment.cpp:54:9:54:14 | call to source | +| arrayassignment.cpp:67:10:67:12 | call to get | arrayassignment.cpp:64:13:64:18 | call to source | +| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source | +| arrayassignment.cpp:135:7:135:10 | ref1 | arrayassignment.cpp:134:9:134:14 | call to source | | copyableclass.cpp:40:8:40:9 | s1 | copyableclass.cpp:34:22:34:27 | call to source | | copyableclass.cpp:41:8:41:9 | s2 | copyableclass.cpp:35:24:35:29 | call to source | | copyableclass.cpp:42:8:42:9 | s3 | copyableclass.cpp:34:22:34:27 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 33da9c34694..e9b37c8a3ee 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -1,3 +1,21 @@ +| arrayassignment.cpp:16:7:16:7 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:17:7:17:10 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:18:7:18:11 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:19:7:19:9 | arrayassignment.cpp:14:9:14:14 | IR only | +| arrayassignment.cpp:31:7:31:7 | arrayassignment.cpp:29:8:29:13 | IR only | +| arrayassignment.cpp:32:7:32:10 | arrayassignment.cpp:29:8:29:13 | IR only | +| arrayassignment.cpp:34:7:34:10 | arrayassignment.cpp:29:8:29:13 | IR only | +| arrayassignment.cpp:56:7:56:8 | arrayassignment.cpp:54:9:54:14 | IR only | +| arrayassignment.cpp:57:10:57:12 | arrayassignment.cpp:54:9:54:14 | AST only | +| arrayassignment.cpp:57:10:57:15 | arrayassignment.cpp:54:9:54:14 | IR only | +| arrayassignment.cpp:66:7:66:8 | arrayassignment.cpp:64:13:64:18 | IR only | +| arrayassignment.cpp:67:10:67:12 | arrayassignment.cpp:64:13:64:18 | AST only | +| arrayassignment.cpp:67:10:67:15 | arrayassignment.cpp:64:13:64:18 | IR only | +| arrayassignment.cpp:136:7:136:13 | arrayassignment.cpp:134:9:134:14 | IR only | +| arrayassignment.cpp:140:7:140:11 | arrayassignment.cpp:139:10:139:15 | IR only | +| arrayassignment.cpp:141:7:141:13 | arrayassignment.cpp:139:10:139:15 | IR only | +| arrayassignment.cpp:145:7:145:13 | arrayassignment.cpp:144:12:144:17 | IR only | +| arrayassignment.cpp:146:7:146:13 | arrayassignment.cpp:144:12:144:17 | IR only | | copyableclass.cpp:40:8:40:9 | copyableclass.cpp:34:22:34:27 | AST only | | copyableclass.cpp:41:8:41:9 | copyableclass.cpp:35:24:35:29 | AST only | | copyableclass.cpp:42:8:42:9 | copyableclass.cpp:34:22:34:27 | AST only | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected index 36926a1b717..ca494a4c2fb 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_ir.expected @@ -1,3 +1,22 @@ +| arrayassignment.cpp:16:7:16:7 | x | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:17:7:17:10 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:18:7:18:11 | * ... | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:19:7:19:9 | (reference dereference) | arrayassignment.cpp:14:9:14:14 | call to source | +| arrayassignment.cpp:31:7:31:7 | x | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:32:7:32:10 | * ... | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:33:7:33:9 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:34:7:34:10 | (reference dereference) | arrayassignment.cpp:29:8:29:13 | call to source | +| arrayassignment.cpp:56:7:56:8 | mi | arrayassignment.cpp:54:9:54:14 | call to source | +| arrayassignment.cpp:57:10:57:15 | (reference dereference) | arrayassignment.cpp:54:9:54:14 | call to source | +| arrayassignment.cpp:66:7:66:8 | mi | arrayassignment.cpp:64:13:64:18 | call to source | +| arrayassignment.cpp:67:10:67:15 | (reference dereference) | arrayassignment.cpp:64:13:64:18 | call to source | +| arrayassignment.cpp:101:7:101:18 | access to array | arrayassignment.cpp:99:17:99:22 | call to source | +| arrayassignment.cpp:135:7:135:10 | (reference dereference) | arrayassignment.cpp:134:9:134:14 | call to source | +| arrayassignment.cpp:136:7:136:13 | access to array | arrayassignment.cpp:134:9:134:14 | call to source | +| arrayassignment.cpp:140:7:140:11 | * ... | arrayassignment.cpp:139:10:139:15 | call to source | +| arrayassignment.cpp:141:7:141:13 | access to array | arrayassignment.cpp:139:10:139:15 | call to source | +| arrayassignment.cpp:145:7:145:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | +| arrayassignment.cpp:146:7:146:13 | access to array | arrayassignment.cpp:144:12:144:17 | call to source | | format.cpp:157:7:157:22 | (int)... | format.cpp:147:12:147:25 | call to source | | format.cpp:157:7:157:22 | access to array | format.cpp:147:12:147:25 | call to source | | format.cpp:158:7:158:27 | ... + ... | format.cpp:148:16:148:30 | call to source | From a5a3078b58a4429c81fdf7480487baf0e1fd394b Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 11:52:07 +0100 Subject: [PATCH 122/146] C++: Add a test case using a typedef int. --- .../dataflow/taint-tests/localTaint.expected | 268 ++++++++++-------- .../dataflow/taint-tests/taint.expected | 18 +- .../dataflow/taint-tests/test_diff.expected | 18 +- .../dataflow/taint-tests/vector.cpp | 21 ++ 4 files changed, 183 insertions(+), 142 deletions(-) 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 ee5b8deddcb..70e7ce3952c 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -316,6 +316,7 @@ | stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | | stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | | stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | +| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | | stl.h:137:53:137:63 | 0 | stl.h:137:46:137:64 | (no string representation) | TAINT | | string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | | | string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT | @@ -2226,129 +2227,144 @@ | vector.cpp:212:8:212:9 | ref arg ff | vector.cpp:213:2:213:2 | ff | | | vector.cpp:212:10:212:10 | call to operator[] [post update] | vector.cpp:212:8:212:9 | ref arg ff | TAINT | | vector.cpp:212:14:212:15 | vs | vector.cpp:212:16:212:16 | call to operator[] | TAINT | -| vector.cpp:219:19:219:20 | call to vector | vector.cpp:221:2:221:3 | v1 | | -| vector.cpp:219:19:219:20 | call to vector | vector.cpp:225:7:225:8 | v1 | | -| vector.cpp:219:19:219:20 | call to vector | vector.cpp:233:13:233:14 | v1 | | -| vector.cpp:219:19:219:20 | call to vector | vector.cpp:233:25:233:26 | v1 | | -| vector.cpp:219:19:219:20 | call to vector | vector.cpp:247:1:247:1 | v1 | | -| vector.cpp:219:23:219:24 | call to vector | vector.cpp:222:2:222:3 | v2 | | -| vector.cpp:219:23:219:24 | call to vector | vector.cpp:226:7:226:8 | v2 | | -| vector.cpp:219:23:219:24 | call to vector | vector.cpp:247:1:247:1 | v2 | | -| vector.cpp:219:27:219:28 | call to vector | vector.cpp:223:2:223:3 | v3 | | -| vector.cpp:219:27:219:28 | call to vector | vector.cpp:227:7:227:8 | v3 | | -| vector.cpp:219:27:219:28 | call to vector | vector.cpp:234:13:234:14 | v3 | | -| vector.cpp:219:27:219:28 | call to vector | vector.cpp:234:25:234:26 | v3 | | -| vector.cpp:219:27:219:28 | call to vector | vector.cpp:235:8:235:9 | v3 | | -| vector.cpp:219:27:219:28 | call to vector | vector.cpp:247:1:247:1 | v3 | | -| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:225:7:225:8 | v1 | | -| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:233:13:233:14 | v1 | | -| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | -| vector.cpp:221:2:221:3 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | -| vector.cpp:221:12:221:14 | 100 | vector.cpp:221:2:221:3 | ref arg v1 | TAINT | -| vector.cpp:221:17:221:17 | 0 | vector.cpp:221:2:221:3 | ref arg v1 | TAINT | -| vector.cpp:222:2:222:3 | ref arg v2 | vector.cpp:226:7:226:8 | v2 | | -| vector.cpp:222:2:222:3 | ref arg v2 | vector.cpp:247:1:247:1 | v2 | | -| vector.cpp:222:12:222:14 | 100 | vector.cpp:222:2:222:3 | ref arg v2 | TAINT | -| vector.cpp:222:17:222:30 | call to source | vector.cpp:222:2:222:3 | ref arg v2 | TAINT | -| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:227:7:227:8 | v3 | | -| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:234:13:234:14 | v3 | | -| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | -| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | -| vector.cpp:223:2:223:3 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | -| vector.cpp:223:15:223:20 | call to source | vector.cpp:223:2:223:3 | ref arg v3 | TAINT | -| vector.cpp:225:7:225:8 | ref arg v1 | vector.cpp:233:13:233:14 | v1 | | -| vector.cpp:225:7:225:8 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | -| vector.cpp:225:7:225:8 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | -| vector.cpp:226:7:226:8 | ref arg v2 | vector.cpp:247:1:247:1 | v2 | | -| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:234:13:234:14 | v3 | | -| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | -| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | -| vector.cpp:227:7:227:8 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | -| vector.cpp:230:20:230:21 | call to vector | vector.cpp:233:3:233:4 | v4 | | -| vector.cpp:230:20:230:21 | call to vector | vector.cpp:241:8:241:9 | v4 | | -| vector.cpp:230:20:230:21 | call to vector | vector.cpp:246:2:246:2 | v4 | | -| vector.cpp:230:24:230:25 | call to vector | vector.cpp:234:3:234:4 | v5 | | -| vector.cpp:230:24:230:25 | call to vector | vector.cpp:242:8:242:9 | v5 | | -| vector.cpp:230:24:230:25 | call to vector | vector.cpp:246:2:246:2 | v5 | | -| vector.cpp:230:28:230:29 | call to vector | vector.cpp:239:3:239:4 | v6 | | -| vector.cpp:230:28:230:29 | call to vector | vector.cpp:245:8:245:9 | v6 | | -| vector.cpp:230:28:230:29 | call to vector | vector.cpp:246:2:246:2 | v6 | | -| vector.cpp:233:3:233:4 | ref arg v4 | vector.cpp:241:8:241:9 | v4 | | -| vector.cpp:233:3:233:4 | ref arg v4 | vector.cpp:246:2:246:2 | v4 | | -| vector.cpp:233:13:233:14 | ref arg v1 | vector.cpp:233:25:233:26 | v1 | | -| vector.cpp:233:13:233:14 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | -| vector.cpp:233:25:233:26 | ref arg v1 | vector.cpp:247:1:247:1 | v1 | | -| vector.cpp:234:3:234:4 | ref arg v5 | vector.cpp:242:8:242:9 | v5 | | -| vector.cpp:234:3:234:4 | ref arg v5 | vector.cpp:246:2:246:2 | v5 | | -| vector.cpp:234:13:234:14 | ref arg v3 | vector.cpp:234:25:234:26 | v3 | | -| vector.cpp:234:13:234:14 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | -| vector.cpp:234:13:234:14 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | -| vector.cpp:234:25:234:26 | ref arg v3 | vector.cpp:235:8:235:9 | v3 | | -| vector.cpp:234:25:234:26 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | -| vector.cpp:235:8:235:9 | ref arg v3 | vector.cpp:247:1:247:1 | v3 | | -| vector.cpp:235:11:235:15 | call to begin | vector.cpp:235:3:235:17 | ... = ... | | -| vector.cpp:235:11:235:15 | call to begin | vector.cpp:236:3:236:4 | i1 | | -| vector.cpp:235:11:235:15 | call to begin | vector.cpp:237:8:237:9 | i1 | | -| vector.cpp:235:11:235:15 | call to begin | vector.cpp:239:13:239:14 | i1 | | -| vector.cpp:235:11:235:15 | call to begin | vector.cpp:243:8:243:9 | i1 | | -| vector.cpp:236:3:236:4 | ref arg i1 | vector.cpp:237:8:237:9 | i1 | | -| vector.cpp:236:3:236:4 | ref arg i1 | vector.cpp:239:13:239:14 | i1 | | -| vector.cpp:236:3:236:4 | ref arg i1 | vector.cpp:243:8:243:9 | i1 | | -| vector.cpp:237:8:237:9 | i1 | vector.cpp:237:3:237:9 | ... = ... | | -| vector.cpp:237:8:237:9 | i1 | vector.cpp:238:3:238:4 | i2 | | -| vector.cpp:237:8:237:9 | i1 | vector.cpp:239:17:239:18 | i2 | | -| vector.cpp:237:8:237:9 | i1 | vector.cpp:244:8:244:9 | i2 | | -| vector.cpp:238:3:238:4 | ref arg i2 | vector.cpp:239:17:239:18 | i2 | | -| vector.cpp:238:3:238:4 | ref arg i2 | vector.cpp:244:8:244:9 | i2 | | -| vector.cpp:239:3:239:4 | ref arg v6 | vector.cpp:245:8:245:9 | v6 | | -| vector.cpp:239:3:239:4 | ref arg v6 | vector.cpp:246:2:246:2 | v6 | | -| vector.cpp:241:8:241:9 | ref arg v4 | vector.cpp:246:2:246:2 | v4 | | -| vector.cpp:242:8:242:9 | ref arg v5 | vector.cpp:246:2:246:2 | v5 | | -| vector.cpp:245:8:245:9 | ref arg v6 | vector.cpp:246:2:246:2 | v6 | | -| vector.cpp:252:19:252:20 | call to vector | vector.cpp:254:2:254:3 | v1 | | -| vector.cpp:252:19:252:20 | call to vector | vector.cpp:255:7:255:8 | v1 | | -| vector.cpp:252:19:252:20 | call to vector | vector.cpp:256:7:256:8 | v1 | | -| vector.cpp:252:19:252:20 | call to vector | vector.cpp:257:7:257:8 | v1 | | -| vector.cpp:252:19:252:20 | call to vector | vector.cpp:263:1:263:1 | v1 | | -| vector.cpp:252:23:252:24 | call to vector | vector.cpp:259:4:259:5 | v2 | | -| vector.cpp:252:23:252:24 | call to vector | vector.cpp:260:7:260:8 | v2 | | -| vector.cpp:252:23:252:24 | call to vector | vector.cpp:261:7:261:8 | v2 | | -| vector.cpp:252:23:252:24 | call to vector | vector.cpp:262:7:262:8 | v2 | | -| vector.cpp:252:23:252:24 | call to vector | vector.cpp:263:1:263:1 | v2 | | -| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:255:7:255:8 | v1 | | -| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:256:7:256:8 | v1 | | -| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | -| vector.cpp:254:2:254:3 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | -| vector.cpp:254:15:254:20 | call to source | vector.cpp:254:2:254:3 | ref arg v1 | TAINT | -| vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:256:7:256:8 | v1 | | -| vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | -| vector.cpp:255:7:255:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | -| vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:257:7:257:8 | v1 | | -| vector.cpp:256:7:256:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | -| vector.cpp:256:7:256:8 | v1 | vector.cpp:256:10:256:13 | call to data | TAINT | -| vector.cpp:256:10:256:13 | ref arg call to data | vector.cpp:256:7:256:8 | ref arg v1 | TAINT | -| vector.cpp:257:7:257:8 | ref arg v1 | vector.cpp:263:1:263:1 | v1 | | -| vector.cpp:257:7:257:8 | v1 | vector.cpp:257:10:257:13 | call to data | TAINT | -| vector.cpp:257:10:257:13 | call to data | vector.cpp:257:7:257:18 | access to array | TAINT | -| vector.cpp:257:17:257:17 | 2 | vector.cpp:257:7:257:18 | access to array | TAINT | -| vector.cpp:259:2:259:13 | * ... [post update] | vector.cpp:259:7:259:10 | call to data [inner post update] | | -| vector.cpp:259:2:259:32 | ... = ... | vector.cpp:259:2:259:13 | * ... [post update] | | -| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:260:7:260:8 | v2 | | -| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | -| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | -| vector.cpp:259:4:259:5 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | -| vector.cpp:259:4:259:5 | v2 | vector.cpp:259:7:259:10 | call to data | TAINT | -| vector.cpp:259:7:259:10 | call to data | vector.cpp:259:2:259:13 | * ... | TAINT | -| vector.cpp:259:7:259:10 | call to data [inner post update] | vector.cpp:259:4:259:5 | ref arg v2 | TAINT | -| vector.cpp:259:17:259:30 | call to source | vector.cpp:259:2:259:32 | ... = ... | | -| vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:261:7:261:8 | v2 | | -| vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | -| vector.cpp:260:7:260:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | -| vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:262:7:262:8 | v2 | | -| vector.cpp:261:7:261:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | -| vector.cpp:261:7:261:8 | v2 | vector.cpp:261:10:261:13 | call to data | TAINT | -| vector.cpp:261:10:261:13 | ref arg call to data | vector.cpp:261:7:261:8 | ref arg v2 | TAINT | -| vector.cpp:262:7:262:8 | ref arg v2 | vector.cpp:263:1:263:1 | v2 | | -| vector.cpp:262:7:262:8 | v2 | vector.cpp:262:10:262:13 | call to data | TAINT | -| vector.cpp:262:10:262:13 | call to data | vector.cpp:262:7:262:18 | access to array | TAINT | -| vector.cpp:262:17:262:17 | 2 | vector.cpp:262:7:262:18 | access to array | TAINT | +| vector.cpp:229:19:229:20 | call to vector | vector.cpp:231:2:231:3 | v1 | | +| vector.cpp:229:19:229:20 | call to vector | vector.cpp:235:7:235:8 | v1 | | +| vector.cpp:229:19:229:20 | call to vector | vector.cpp:243:13:243:14 | v1 | | +| vector.cpp:229:19:229:20 | call to vector | vector.cpp:243:25:243:26 | v1 | | +| vector.cpp:229:19:229:20 | call to vector | vector.cpp:268:1:268:1 | v1 | | +| vector.cpp:229:23:229:24 | call to vector | vector.cpp:232:2:232:3 | v2 | | +| vector.cpp:229:23:229:24 | call to vector | vector.cpp:236:7:236:8 | v2 | | +| vector.cpp:229:23:229:24 | call to vector | vector.cpp:268:1:268:1 | v2 | | +| vector.cpp:229:27:229:28 | call to vector | vector.cpp:233:2:233:3 | v3 | | +| vector.cpp:229:27:229:28 | call to vector | vector.cpp:237:7:237:8 | v3 | | +| vector.cpp:229:27:229:28 | call to vector | vector.cpp:244:13:244:14 | v3 | | +| vector.cpp:229:27:229:28 | call to vector | vector.cpp:244:25:244:26 | v3 | | +| vector.cpp:229:27:229:28 | call to vector | vector.cpp:245:8:245:9 | v3 | | +| vector.cpp:229:27:229:28 | call to vector | vector.cpp:268:1:268:1 | v3 | | +| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:235:7:235:8 | v1 | | +| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:243:13:243:14 | v1 | | +| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:243:25:243:26 | v1 | | +| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | +| vector.cpp:231:12:231:14 | 100 | vector.cpp:231:2:231:3 | ref arg v1 | TAINT | +| vector.cpp:231:17:231:17 | 0 | vector.cpp:231:2:231:3 | ref arg v1 | TAINT | +| vector.cpp:232:2:232:3 | ref arg v2 | vector.cpp:236:7:236:8 | v2 | | +| vector.cpp:232:2:232:3 | ref arg v2 | vector.cpp:268:1:268:1 | v2 | | +| vector.cpp:232:12:232:14 | 100 | vector.cpp:232:2:232:3 | ref arg v2 | TAINT | +| vector.cpp:232:17:232:30 | call to source | vector.cpp:232:2:232:3 | ref arg v2 | TAINT | +| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:237:7:237:8 | v3 | | +| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:244:13:244:14 | v3 | | +| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:244:25:244:26 | v3 | | +| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | +| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | +| vector.cpp:233:15:233:20 | call to source | vector.cpp:233:2:233:3 | ref arg v3 | TAINT | +| vector.cpp:235:7:235:8 | ref arg v1 | vector.cpp:243:13:243:14 | v1 | | +| vector.cpp:235:7:235:8 | ref arg v1 | vector.cpp:243:25:243:26 | v1 | | +| vector.cpp:235:7:235:8 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | +| vector.cpp:236:7:236:8 | ref arg v2 | vector.cpp:268:1:268:1 | v2 | | +| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:244:13:244:14 | v3 | | +| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:244:25:244:26 | v3 | | +| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | +| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | +| vector.cpp:240:20:240:21 | call to vector | vector.cpp:243:3:243:4 | v4 | | +| vector.cpp:240:20:240:21 | call to vector | vector.cpp:251:8:251:9 | v4 | | +| vector.cpp:240:20:240:21 | call to vector | vector.cpp:256:2:256:2 | v4 | | +| vector.cpp:240:24:240:25 | call to vector | vector.cpp:244:3:244:4 | v5 | | +| vector.cpp:240:24:240:25 | call to vector | vector.cpp:252:8:252:9 | v5 | | +| vector.cpp:240:24:240:25 | call to vector | vector.cpp:256:2:256:2 | v5 | | +| vector.cpp:240:28:240:29 | call to vector | vector.cpp:249:3:249:4 | v6 | | +| vector.cpp:240:28:240:29 | call to vector | vector.cpp:255:8:255:9 | v6 | | +| vector.cpp:240:28:240:29 | call to vector | vector.cpp:256:2:256:2 | v6 | | +| vector.cpp:243:3:243:4 | ref arg v4 | vector.cpp:251:8:251:9 | v4 | | +| vector.cpp:243:3:243:4 | ref arg v4 | vector.cpp:256:2:256:2 | v4 | | +| vector.cpp:243:13:243:14 | ref arg v1 | vector.cpp:243:25:243:26 | v1 | | +| vector.cpp:243:13:243:14 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | +| vector.cpp:243:25:243:26 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | +| vector.cpp:244:3:244:4 | ref arg v5 | vector.cpp:252:8:252:9 | v5 | | +| vector.cpp:244:3:244:4 | ref arg v5 | vector.cpp:256:2:256:2 | v5 | | +| vector.cpp:244:13:244:14 | ref arg v3 | vector.cpp:244:25:244:26 | v3 | | +| vector.cpp:244:13:244:14 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | +| vector.cpp:244:13:244:14 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | +| vector.cpp:244:25:244:26 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | +| vector.cpp:244:25:244:26 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | +| vector.cpp:245:8:245:9 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | +| vector.cpp:245:11:245:15 | call to begin | vector.cpp:245:3:245:17 | ... = ... | | +| vector.cpp:245:11:245:15 | call to begin | vector.cpp:246:3:246:4 | i1 | | +| vector.cpp:245:11:245:15 | call to begin | vector.cpp:247:8:247:9 | i1 | | +| vector.cpp:245:11:245:15 | call to begin | vector.cpp:249:13:249:14 | i1 | | +| vector.cpp:245:11:245:15 | call to begin | vector.cpp:253:8:253:9 | i1 | | +| vector.cpp:246:3:246:4 | ref arg i1 | vector.cpp:247:8:247:9 | i1 | | +| vector.cpp:246:3:246:4 | ref arg i1 | vector.cpp:249:13:249:14 | i1 | | +| vector.cpp:246:3:246:4 | ref arg i1 | vector.cpp:253:8:253:9 | i1 | | +| vector.cpp:247:8:247:9 | i1 | vector.cpp:247:3:247:9 | ... = ... | | +| vector.cpp:247:8:247:9 | i1 | vector.cpp:248:3:248:4 | i2 | | +| vector.cpp:247:8:247:9 | i1 | vector.cpp:249:17:249:18 | i2 | | +| vector.cpp:247:8:247:9 | i1 | vector.cpp:254:8:254:9 | i2 | | +| vector.cpp:248:3:248:4 | ref arg i2 | vector.cpp:249:17:249:18 | i2 | | +| vector.cpp:248:3:248:4 | ref arg i2 | vector.cpp:254:8:254:9 | i2 | | +| vector.cpp:249:3:249:4 | ref arg v6 | vector.cpp:255:8:255:9 | v6 | | +| vector.cpp:249:3:249:4 | ref arg v6 | vector.cpp:256:2:256:2 | v6 | | +| vector.cpp:251:8:251:9 | ref arg v4 | vector.cpp:256:2:256:2 | v4 | | +| vector.cpp:252:8:252:9 | ref arg v5 | vector.cpp:256:2:256:2 | v5 | | +| vector.cpp:255:8:255:9 | ref arg v6 | vector.cpp:256:2:256:2 | v6 | | +| vector.cpp:259:22:259:23 | call to vector | vector.cpp:262:3:262:4 | v7 | | +| vector.cpp:259:22:259:23 | call to vector | vector.cpp:265:8:265:9 | v7 | | +| vector.cpp:259:22:259:23 | call to vector | vector.cpp:267:2:267:2 | v7 | | +| vector.cpp:260:24:260:25 | call to vector | vector.cpp:263:3:263:4 | v8 | | +| vector.cpp:260:24:260:25 | call to vector | vector.cpp:266:8:266:9 | v8 | | +| vector.cpp:260:24:260:25 | call to vector | vector.cpp:267:2:267:2 | v8 | | +| vector.cpp:262:3:262:4 | ref arg v7 | vector.cpp:265:8:265:9 | v7 | | +| vector.cpp:262:3:262:4 | ref arg v7 | vector.cpp:267:2:267:2 | v7 | | +| vector.cpp:262:13:262:15 | 100 | vector.cpp:262:3:262:4 | ref arg v7 | TAINT | +| vector.cpp:262:18:262:31 | call to source | vector.cpp:262:3:262:4 | ref arg v7 | TAINT | +| vector.cpp:263:3:263:4 | ref arg v8 | vector.cpp:266:8:266:9 | v8 | | +| vector.cpp:263:3:263:4 | ref arg v8 | vector.cpp:267:2:267:2 | v8 | | +| vector.cpp:263:18:263:35 | call to source | vector.cpp:263:3:263:4 | ref arg v8 | TAINT | +| vector.cpp:265:8:265:9 | ref arg v7 | vector.cpp:267:2:267:2 | v7 | | +| vector.cpp:266:8:266:9 | ref arg v8 | vector.cpp:267:2:267:2 | v8 | | +| vector.cpp:273:19:273:20 | call to vector | vector.cpp:275:2:275:3 | v1 | | +| vector.cpp:273:19:273:20 | call to vector | vector.cpp:276:7:276:8 | v1 | | +| vector.cpp:273:19:273:20 | call to vector | vector.cpp:277:7:277:8 | v1 | | +| vector.cpp:273:19:273:20 | call to vector | vector.cpp:278:7:278:8 | v1 | | +| vector.cpp:273:19:273:20 | call to vector | vector.cpp:284:1:284:1 | v1 | | +| vector.cpp:273:23:273:24 | call to vector | vector.cpp:280:4:280:5 | v2 | | +| vector.cpp:273:23:273:24 | call to vector | vector.cpp:281:7:281:8 | v2 | | +| vector.cpp:273:23:273:24 | call to vector | vector.cpp:282:7:282:8 | v2 | | +| vector.cpp:273:23:273:24 | call to vector | vector.cpp:283:7:283:8 | v2 | | +| vector.cpp:273:23:273:24 | call to vector | vector.cpp:284:1:284:1 | v2 | | +| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:276:7:276:8 | v1 | | +| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:277:7:277:8 | v1 | | +| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:278:7:278:8 | v1 | | +| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | +| vector.cpp:275:15:275:20 | call to source | vector.cpp:275:2:275:3 | ref arg v1 | TAINT | +| vector.cpp:276:7:276:8 | ref arg v1 | vector.cpp:277:7:277:8 | v1 | | +| vector.cpp:276:7:276:8 | ref arg v1 | vector.cpp:278:7:278:8 | v1 | | +| vector.cpp:276:7:276:8 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | +| vector.cpp:277:7:277:8 | ref arg v1 | vector.cpp:278:7:278:8 | v1 | | +| vector.cpp:277:7:277:8 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | +| vector.cpp:277:7:277:8 | v1 | vector.cpp:277:10:277:13 | call to data | TAINT | +| vector.cpp:277:10:277:13 | ref arg call to data | vector.cpp:277:7:277:8 | ref arg v1 | TAINT | +| vector.cpp:278:7:278:8 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | +| vector.cpp:278:7:278:8 | v1 | vector.cpp:278:10:278:13 | call to data | TAINT | +| vector.cpp:278:10:278:13 | call to data | vector.cpp:278:7:278:18 | access to array | TAINT | +| vector.cpp:278:17:278:17 | 2 | vector.cpp:278:7:278:18 | access to array | TAINT | +| vector.cpp:280:2:280:13 | * ... [post update] | vector.cpp:280:7:280:10 | call to data [inner post update] | | +| vector.cpp:280:2:280:32 | ... = ... | vector.cpp:280:2:280:13 | * ... [post update] | | +| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:281:7:281:8 | v2 | | +| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:282:7:282:8 | v2 | | +| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:283:7:283:8 | v2 | | +| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | +| vector.cpp:280:4:280:5 | v2 | vector.cpp:280:7:280:10 | call to data | TAINT | +| vector.cpp:280:7:280:10 | call to data | vector.cpp:280:2:280:13 | * ... | TAINT | +| vector.cpp:280:7:280:10 | call to data [inner post update] | vector.cpp:280:4:280:5 | ref arg v2 | TAINT | +| vector.cpp:280:17:280:30 | call to source | vector.cpp:280:2:280:32 | ... = ... | | +| vector.cpp:281:7:281:8 | ref arg v2 | vector.cpp:282:7:282:8 | v2 | | +| vector.cpp:281:7:281:8 | ref arg v2 | vector.cpp:283:7:283:8 | v2 | | +| vector.cpp:281:7:281:8 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | +| vector.cpp:282:7:282:8 | ref arg v2 | vector.cpp:283:7:283:8 | v2 | | +| vector.cpp:282:7:282:8 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | +| vector.cpp:282:7:282:8 | v2 | vector.cpp:282:10:282:13 | call to data | TAINT | +| vector.cpp:282:10:282:13 | ref arg call to data | vector.cpp:282:7:282:8 | ref arg v2 | TAINT | +| vector.cpp:283:7:283:8 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | +| vector.cpp:283:7:283:8 | v2 | vector.cpp:283:10:283:13 | call to data | TAINT | +| vector.cpp:283:10:283:13 | call to data | vector.cpp:283:7:283:18 | access to array | TAINT | +| vector.cpp:283:17:283:17 | 2 | vector.cpp:283:7:283:18 | access to array | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index daaadcfe6f1..c82a1134c7f 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -241,11 +241,13 @@ | vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | | vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | -| vector.cpp:226:7:226:8 | v2 | vector.cpp:222:17:222:30 | call to source | -| vector.cpp:227:7:227:8 | v3 | vector.cpp:223:15:223:20 | call to source | -| vector.cpp:255:7:255:8 | v1 | vector.cpp:254:15:254:20 | call to source | -| vector.cpp:256:10:256:13 | call to data | vector.cpp:254:15:254:20 | call to source | -| vector.cpp:257:7:257:18 | access to array | vector.cpp:254:15:254:20 | call to source | -| vector.cpp:260:7:260:8 | v2 | vector.cpp:259:17:259:30 | call to source | -| vector.cpp:261:10:261:13 | call to data | vector.cpp:259:17:259:30 | call to source | -| vector.cpp:262:7:262:18 | access to array | vector.cpp:259:17:259:30 | call to source | +| vector.cpp:236:7:236:8 | v2 | vector.cpp:232:17:232:30 | call to source | +| vector.cpp:237:7:237:8 | v3 | vector.cpp:233:15:233:20 | call to source | +| vector.cpp:265:8:265:9 | v7 | vector.cpp:262:18:262:31 | call to source | +| vector.cpp:266:8:266:9 | v8 | vector.cpp:263:18:263:35 | call to source | +| vector.cpp:276:7:276:8 | v1 | vector.cpp:275:15:275:20 | call to source | +| vector.cpp:277:10:277:13 | call to data | vector.cpp:275:15:275:20 | call to source | +| vector.cpp:278:7:278:18 | access to array | vector.cpp:275:15:275:20 | call to source | +| vector.cpp:281:7:281:8 | v2 | vector.cpp:280:17:280:30 | call to source | +| vector.cpp:282:10:282:13 | call to data | vector.cpp:280:17:280:30 | call to source | +| vector.cpp:283:7:283:18 | access to array | vector.cpp:280:17:280:30 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index eb5167415cb..e909d08e97e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -177,11 +177,13 @@ | vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | | vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | -| vector.cpp:226:7:226:8 | vector.cpp:222:17:222:30 | AST only | -| vector.cpp:227:7:227:8 | vector.cpp:223:15:223:20 | AST only | -| vector.cpp:255:7:255:8 | vector.cpp:254:15:254:20 | AST only | -| vector.cpp:256:10:256:13 | vector.cpp:254:15:254:20 | AST only | -| vector.cpp:257:7:257:18 | vector.cpp:254:15:254:20 | AST only | -| vector.cpp:260:7:260:8 | vector.cpp:259:17:259:30 | AST only | -| vector.cpp:261:10:261:13 | vector.cpp:259:17:259:30 | AST only | -| vector.cpp:262:7:262:18 | vector.cpp:259:17:259:30 | AST only | +| vector.cpp:236:7:236:8 | vector.cpp:232:17:232:30 | AST only | +| vector.cpp:237:7:237:8 | vector.cpp:233:15:233:20 | AST only | +| vector.cpp:265:8:265:9 | vector.cpp:262:18:262:31 | AST only | +| vector.cpp:266:8:266:9 | vector.cpp:263:18:263:35 | AST only | +| vector.cpp:276:7:276:8 | vector.cpp:275:15:275:20 | AST only | +| vector.cpp:277:10:277:13 | vector.cpp:275:15:275:20 | AST only | +| vector.cpp:278:7:278:18 | vector.cpp:275:15:275:20 | AST only | +| vector.cpp:281:7:281:8 | vector.cpp:280:17:280:30 | AST only | +| vector.cpp:282:10:282:13 | vector.cpp:280:17:280:30 | AST only | +| vector.cpp:283:7:283:18 | vector.cpp:280:17:280:30 | AST only | 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 4f2c3168269..bb1c6ef5dcf 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -215,6 +215,16 @@ void test_nested_vectors() void sink(std::vector::iterator &); +typedef int myInt; +typedef float myFloat; + +namespace ns_myFloat +{ + myFloat source(); +} + +void sink(std::vector &); + void test_vector_assign() { std::vector v1, v2, v3; @@ -244,6 +254,17 @@ void test_vector_assign() { sink(i2); // tainted [NOT DETECTED] sink(v6); // tainted [NOT DETECTED] } + + { + std::vector v7; + std::vector v8; + + v7.assign(100, ns_int::source()); + v8.assign(100, ns_myFloat::source()); + + sink(v7); // tainted + sink(v8); // tainted + } } void sink(int *); From 9da6da6106e8f1d096786c17938a170b26829cbe Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 27 Aug 2020 13:29:41 +0200 Subject: [PATCH 123/146] Python: Fix imports in shraed dataflow tests --- python/ql/test/experimental/dataflow/callGraphConfig.qll | 1 + .../ql/test/experimental/dataflow/coverage/argumentRouting1.ql | 1 + .../ql/test/experimental/dataflow/coverage/argumentRouting2.ql | 1 + .../ql/test/experimental/dataflow/coverage/argumentRouting3.ql | 1 + .../ql/test/experimental/dataflow/coverage/argumentRouting4.ql | 1 + python/ql/test/experimental/dataflow/coverage/dataflow.ql | 1 + python/ql/test/experimental/dataflow/regression/dataflow.ql | 1 + python/ql/test/experimental/dataflow/testConfig.qll | 1 + 8 files changed, 8 insertions(+) diff --git a/python/ql/test/experimental/dataflow/callGraphConfig.qll b/python/ql/test/experimental/dataflow/callGraphConfig.qll index 241b7b9478c..0060c030c72 100644 --- a/python/ql/test/experimental/dataflow/callGraphConfig.qll +++ b/python/ql/test/experimental/dataflow/callGraphConfig.qll @@ -1,3 +1,4 @@ +private import python import experimental.dataflow.DataFlow /** diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql index 79bed33d4c7..d2a8a0c4baf 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting1.ql @@ -1,3 +1,4 @@ +import python import experimental.dataflow.DataFlow /** diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting2.ql b/python/ql/test/experimental/dataflow/coverage/argumentRouting2.ql index 5ab8a4e7f6d..4baa3b35714 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting2.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting2.ql @@ -1,3 +1,4 @@ +import python import experimental.dataflow.DataFlow /** diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting3.ql b/python/ql/test/experimental/dataflow/coverage/argumentRouting3.ql index f29a733b2ce..3aa76402a74 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting3.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting3.ql @@ -1,3 +1,4 @@ +import python import experimental.dataflow.DataFlow /** diff --git a/python/ql/test/experimental/dataflow/coverage/argumentRouting4.ql b/python/ql/test/experimental/dataflow/coverage/argumentRouting4.ql index ad9da22fb24..a4ae253de6c 100644 --- a/python/ql/test/experimental/dataflow/coverage/argumentRouting4.ql +++ b/python/ql/test/experimental/dataflow/coverage/argumentRouting4.ql @@ -1,3 +1,4 @@ +import python import experimental.dataflow.DataFlow /** diff --git a/python/ql/test/experimental/dataflow/coverage/dataflow.ql b/python/ql/test/experimental/dataflow/coverage/dataflow.ql index 1347c440496..18b21324e47 100644 --- a/python/ql/test/experimental/dataflow/coverage/dataflow.ql +++ b/python/ql/test/experimental/dataflow/coverage/dataflow.ql @@ -2,6 +2,7 @@ * @kind path-problem */ +import python import experimental.dataflow.testConfig import DataFlow::PathGraph diff --git a/python/ql/test/experimental/dataflow/regression/dataflow.ql b/python/ql/test/experimental/dataflow/regression/dataflow.ql index a5a933bdc71..c95b2f2111f 100644 --- a/python/ql/test/experimental/dataflow/regression/dataflow.ql +++ b/python/ql/test/experimental/dataflow/regression/dataflow.ql @@ -5,6 +5,7 @@ * hope to remove the false positive. */ +import python import experimental.dataflow.testConfig from DataFlow::Node source, DataFlow::Node sink diff --git a/python/ql/test/experimental/dataflow/testConfig.qll b/python/ql/test/experimental/dataflow/testConfig.qll index 178f2f4f229..f2e35ab9d1c 100644 --- a/python/ql/test/experimental/dataflow/testConfig.qll +++ b/python/ql/test/experimental/dataflow/testConfig.qll @@ -20,6 +20,7 @@ * complex | `42j` (not supported yet) */ +private import python import experimental.dataflow.DataFlow class TestConfiguration extends DataFlow::Configuration { From dccbcc15b3654f2ebd1d12708c5cf89cf9ce48b8 Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 27 Aug 2020 13:35:24 +0200 Subject: [PATCH 124/146] Python: Sync InlineExpectationsTest.qll between Python and C++ Also changes `valuesasas` to `values` in the test example. --- config/identical-files.json | 4 ++++ cpp/ql/test/TestUtilities/InlineExpectationsTest.qll | 4 ++-- python/ql/test/TestUtilities/InlineExpectationsTest.qll | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/config/identical-files.json b/config/identical-files.json index 71c507e3993..b011be4d97d 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -325,6 +325,10 @@ "csharp/ql/src/experimental/ir/implementation/raw/gvn/internal/ValueNumberingImports.qll", "csharp/ql/src/experimental/ir/implementation/unaliased_ssa/gvn/internal/ValueNumberingImports.qll" ], + "Inline Test Expectations": [ + "cpp/ql/test/TestUtilities/InlineExpectationsTest.qll", + "python/ql/test/TestUtilities/InlineExpectationsTest.qll" + ], "XML": [ "cpp/ql/src/semmle/code/cpp/XML.qll", "csharp/ql/src/semmle/code/csharp/XML.qll", diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll index 150c898bdbd..9a1eef83d4f 100644 --- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -28,11 +28,11 @@ * } * * override predicate hasActualResult( - * Location location, string element, string tag, string valuesasas + * Location location, string element, string tag, string values * ) { * exists(Expr e | * tag = "const" and // The tag for this test. - * valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions. + * values = 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. * ) diff --git a/python/ql/test/TestUtilities/InlineExpectationsTest.qll b/python/ql/test/TestUtilities/InlineExpectationsTest.qll index 150c898bdbd..9a1eef83d4f 100644 --- a/python/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/python/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -28,11 +28,11 @@ * } * * override predicate hasActualResult( - * Location location, string element, string tag, string valuesasas + * Location location, string element, string tag, string values * ) { * exists(Expr e | * tag = "const" and // The tag for this test. - * valuesasas = e.getValue() and // The expected value. Will only hold for constant expressions. + * values = 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. * ) From 797e290a6778930fe4f4133428fbfac54915935f Mon Sep 17 00:00:00 2001 From: Taus Brock-Nannestad Date: Thu, 27 Aug 2020 14:12:40 +0200 Subject: [PATCH 125/146] Python+CPP: Change `values` to `value` --- cpp/ql/test/TestUtilities/InlineExpectationsTest.qll | 4 ++-- python/ql/test/TestUtilities/InlineExpectationsTest.qll | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll index 9a1eef83d4f..9e30de327f8 100644 --- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -28,11 +28,11 @@ * } * * override predicate hasActualResult( - * Location location, string element, string tag, string values + * Location location, string element, string tag, string value * ) { * exists(Expr e | * tag = "const" and // The tag for this test. - * values = e.getValue() and // The expected value. Will only hold for constant expressions. + * 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. * ) diff --git a/python/ql/test/TestUtilities/InlineExpectationsTest.qll b/python/ql/test/TestUtilities/InlineExpectationsTest.qll index 9a1eef83d4f..9e30de327f8 100644 --- a/python/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/python/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -28,11 +28,11 @@ * } * * override predicate hasActualResult( - * Location location, string element, string tag, string values + * Location location, string element, string tag, string value * ) { * exists(Expr e | * tag = "const" and // The tag for this test. - * values = e.getValue() and // The expected value. Will only hold for constant expressions. + * 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. * ) From fcd426210f791a2619e7d7146a1ff8e265554bc3 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 27 Aug 2020 14:43:16 +0200 Subject: [PATCH 126/146] C#: Add missing QlDoc for code duplication --- csharp/ql/src/external/CodeDuplication.qll | 25 ++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/csharp/ql/src/external/CodeDuplication.qll b/csharp/ql/src/external/CodeDuplication.qll index 53ff9e91c1c..25dac79bd8c 100644 --- a/csharp/ql/src/external/CodeDuplication.qll +++ b/csharp/ql/src/external/CodeDuplication.qll @@ -66,9 +66,9 @@ class SimilarBlock extends Copy, @similarity { } } -Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) } +private Method sourceMethod() { method_location(result, _) and numlines(result, _, _, _) } -int numberOfSourceMethods(Class c) { +private int numberOfSourceMethods(Class c) { result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c) } @@ -97,6 +97,7 @@ private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) { ) } +/** Holds if `duplicate` number of statements are duplicated in the methods. */ predicate duplicateStatements(Method m1, Method m2, int duplicate, int total) { duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and total = strictcount(statementInMethod(m1)) @@ -109,7 +110,7 @@ predicate duplicateMethod(Method m, Method other) { exists(int total | duplicateStatements(m, other, total, total)) } -predicate similarLines(File f, int line) { +private predicate similarLines(File f, int line) { exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]) } @@ -148,7 +149,7 @@ private predicate similarLinesCovered(File f, int coveredLines, File otherFile) ) } -predicate duplicateLines(File f, int line) { +private predicate duplicateLines(File f, int line) { exists(DuplicateBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()] ) @@ -189,6 +190,7 @@ private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile ) } +/** Holds if the two files are not duplicated but have more than 80% similar lines. */ predicate similarFiles(File f, File other, int percent) { exists(int covered, int total | similarLinesCovered(f, covered, other) and @@ -199,6 +201,7 @@ predicate similarFiles(File f, File other, int percent) { not duplicateFiles(f, other, _) } +/** Holds if the two files have more than 70% duplicated lines. */ predicate duplicateFiles(File f, File other, int percent) { exists(int covered, int total | duplicateLinesCovered(f, covered, other) and @@ -209,7 +212,7 @@ predicate duplicateFiles(File f, File other, int percent) { } pragma[noopt] -predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) { +private predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) { exists(int numDup | numDup = strictcount(Method m1 | @@ -248,6 +251,7 @@ private predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int not other instanceof AnonymousClass } +/** Holds if the methods in the two classes are more than 80% duplicated. */ predicate mostlyDuplicateClass(Class c, Class other, string message) { exists(int numDup, int total | mostlyDuplicateClassBase(c, other, numDup, total) and @@ -272,19 +276,28 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) { ) } +/** Holds if the two files are similar or duplated. */ predicate fileLevelDuplication(File f, File other) { similarFiles(f, other, _) or duplicateFiles(f, other, _) } +/** + * Holds if the two classes are duplicated anonymous classes or more than 80% of + * their methods are duplicated. + */ predicate classLevelDuplication(Class c, Class other) { duplicateAnonymousClass(c, other) or mostlyDuplicateClass(c, other, _) } -Element whitelistedDuplicateElement() { +private Element whitelistedDuplicateElement() { result instanceof UsingNamespaceDirective or result instanceof UsingStaticDirective } +/** + * Holds if the `line` in the `file` contains an element, such as a `using` + * directive, that is not considered for code duplication. + */ predicate whitelistedLineForDuplication(File file, int line) { exists(Location loc | loc = whitelistedDuplicateElement().getLocation() | line = loc.getStartLine() and file = loc.getFile() From 7e2cf9a8583808dc1f0f5a96ae8c70506b322c08 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 27 Aug 2020 15:11:55 +0200 Subject: [PATCH 127/146] Adjust code review findings --- .../Entities/Instruction.cs | 4 ++-- .../Semmle.Extraction.CIL/Entities/Method.cs | 21 +++++++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 1c5607a23ab..072ccc4ab84 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -419,14 +419,14 @@ namespace Semmle.Extraction.CIL.Entities break; case Payload.Arg8: case Payload.Arg16: - if (!(Method.Parameters is null)) + if (Method.Parameters is object) { yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]); } break; case Payload.Local8: case Payload.Local16: - if (!(Method.LocalVariables is null)) + if (Method.LocalVariables is object) { yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs index ba1ede610c2..1dd3d4a6c44 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Method.cs @@ -45,7 +45,7 @@ namespace Semmle.Extraction.CIL.Entities public abstract string Name { get; } public virtual IList? LocalVariables => throw new NotImplementedException(); - public IList? Parameters { get; private set; } + public IList? Parameters { get; protected set; } public override void WriteId(TextWriter trapFile) => WriteMethodId(trapFile, DeclaringType, NameLabel); @@ -76,11 +76,6 @@ namespace Semmle.Extraction.CIL.Entities public override string IdSuffix => ";cil-method"; - protected void PopulateParameters(IEnumerable parameterTypes) - { - Parameters = MakeParameters(parameterTypes).ToArray(); - } - protected IEnumerable PopulateFlags { get @@ -92,7 +87,7 @@ namespace Semmle.Extraction.CIL.Entities public abstract bool IsStatic { get; } - private IEnumerable MakeParameters(IEnumerable parameterTypes) + protected IEnumerable MakeParameters(IEnumerable parameterTypes) { int i = 0; @@ -206,9 +201,9 @@ namespace Semmle.Extraction.CIL.Entities var typeSignature = md.DecodeSignature(cx.TypeSignatureDecoder, this); - PopulateParameters(typeSignature.ParameterTypes); + Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray(); - foreach (var c in Parameters!) + foreach (var c in Parameters) yield return c; foreach (var c in PopulateFlags) @@ -466,8 +461,8 @@ namespace Semmle.Extraction.CIL.Entities var typeSignature = mr.DecodeMethodSignature(cx.TypeSignatureDecoder, this); - PopulateParameters(typeSignature.ParameterTypes); - foreach (var p in Parameters!) yield return p; + Parameters = MakeParameters(typeSignature.ParameterTypes).ToArray(); + foreach (var p in Parameters) yield return p; foreach (var f in PopulateFlags) yield return f; @@ -550,8 +545,8 @@ namespace Semmle.Extraction.CIL.Entities throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}"); } - PopulateParameters(constructedTypeSignature.ParameterTypes); - foreach (var p in Parameters!) + Parameters = MakeParameters(constructedTypeSignature.ParameterTypes).ToArray(); + foreach (var p in Parameters) yield return p; foreach (var f in PopulateFlags) From 816b8abd7cf8d3963fe8cc2f768a08b0b1f57acb Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 13:42:11 +0100 Subject: [PATCH 128/146] C++: Add a test case using a const int *. --- .../dataflow/taint-tests/localTaint.expected | 289 +++++++++--------- .../dataflow/taint-tests/taint.expected | 20 +- .../dataflow/taint-tests/test_diff.expected | 20 +- .../dataflow/taint-tests/vector.cpp | 9 + 4 files changed, 177 insertions(+), 161 deletions(-) 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 70e7ce3952c..198c1e914ba 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -317,6 +317,7 @@ | stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | | stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | | stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | +| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | | stl.h:137:53:137:63 | 0 | stl.h:137:46:137:64 | (no string representation) | TAINT | | string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | | | string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT | @@ -2227,144 +2228,150 @@ | vector.cpp:212:8:212:9 | ref arg ff | vector.cpp:213:2:213:2 | ff | | | vector.cpp:212:10:212:10 | call to operator[] [post update] | vector.cpp:212:8:212:9 | ref arg ff | TAINT | | vector.cpp:212:14:212:15 | vs | vector.cpp:212:16:212:16 | call to operator[] | TAINT | -| vector.cpp:229:19:229:20 | call to vector | vector.cpp:231:2:231:3 | v1 | | -| vector.cpp:229:19:229:20 | call to vector | vector.cpp:235:7:235:8 | v1 | | -| vector.cpp:229:19:229:20 | call to vector | vector.cpp:243:13:243:14 | v1 | | -| vector.cpp:229:19:229:20 | call to vector | vector.cpp:243:25:243:26 | v1 | | -| vector.cpp:229:19:229:20 | call to vector | vector.cpp:268:1:268:1 | v1 | | -| vector.cpp:229:23:229:24 | call to vector | vector.cpp:232:2:232:3 | v2 | | -| vector.cpp:229:23:229:24 | call to vector | vector.cpp:236:7:236:8 | v2 | | -| vector.cpp:229:23:229:24 | call to vector | vector.cpp:268:1:268:1 | v2 | | -| vector.cpp:229:27:229:28 | call to vector | vector.cpp:233:2:233:3 | v3 | | -| vector.cpp:229:27:229:28 | call to vector | vector.cpp:237:7:237:8 | v3 | | -| vector.cpp:229:27:229:28 | call to vector | vector.cpp:244:13:244:14 | v3 | | -| vector.cpp:229:27:229:28 | call to vector | vector.cpp:244:25:244:26 | v3 | | -| vector.cpp:229:27:229:28 | call to vector | vector.cpp:245:8:245:9 | v3 | | -| vector.cpp:229:27:229:28 | call to vector | vector.cpp:268:1:268:1 | v3 | | -| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:235:7:235:8 | v1 | | -| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:243:13:243:14 | v1 | | -| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:243:25:243:26 | v1 | | -| vector.cpp:231:2:231:3 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | -| vector.cpp:231:12:231:14 | 100 | vector.cpp:231:2:231:3 | ref arg v1 | TAINT | -| vector.cpp:231:17:231:17 | 0 | vector.cpp:231:2:231:3 | ref arg v1 | TAINT | -| vector.cpp:232:2:232:3 | ref arg v2 | vector.cpp:236:7:236:8 | v2 | | -| vector.cpp:232:2:232:3 | ref arg v2 | vector.cpp:268:1:268:1 | v2 | | -| vector.cpp:232:12:232:14 | 100 | vector.cpp:232:2:232:3 | ref arg v2 | TAINT | -| vector.cpp:232:17:232:30 | call to source | vector.cpp:232:2:232:3 | ref arg v2 | TAINT | -| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:237:7:237:8 | v3 | | -| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:244:13:244:14 | v3 | | -| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:244:25:244:26 | v3 | | -| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | -| vector.cpp:233:2:233:3 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | -| vector.cpp:233:15:233:20 | call to source | vector.cpp:233:2:233:3 | ref arg v3 | TAINT | -| vector.cpp:235:7:235:8 | ref arg v1 | vector.cpp:243:13:243:14 | v1 | | -| vector.cpp:235:7:235:8 | ref arg v1 | vector.cpp:243:25:243:26 | v1 | | -| vector.cpp:235:7:235:8 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | -| vector.cpp:236:7:236:8 | ref arg v2 | vector.cpp:268:1:268:1 | v2 | | -| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:244:13:244:14 | v3 | | -| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:244:25:244:26 | v3 | | -| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | -| vector.cpp:237:7:237:8 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | -| vector.cpp:240:20:240:21 | call to vector | vector.cpp:243:3:243:4 | v4 | | -| vector.cpp:240:20:240:21 | call to vector | vector.cpp:251:8:251:9 | v4 | | -| vector.cpp:240:20:240:21 | call to vector | vector.cpp:256:2:256:2 | v4 | | -| vector.cpp:240:24:240:25 | call to vector | vector.cpp:244:3:244:4 | v5 | | -| vector.cpp:240:24:240:25 | call to vector | vector.cpp:252:8:252:9 | v5 | | -| vector.cpp:240:24:240:25 | call to vector | vector.cpp:256:2:256:2 | v5 | | -| vector.cpp:240:28:240:29 | call to vector | vector.cpp:249:3:249:4 | v6 | | -| vector.cpp:240:28:240:29 | call to vector | vector.cpp:255:8:255:9 | v6 | | -| vector.cpp:240:28:240:29 | call to vector | vector.cpp:256:2:256:2 | v6 | | -| vector.cpp:243:3:243:4 | ref arg v4 | vector.cpp:251:8:251:9 | v4 | | -| vector.cpp:243:3:243:4 | ref arg v4 | vector.cpp:256:2:256:2 | v4 | | -| vector.cpp:243:13:243:14 | ref arg v1 | vector.cpp:243:25:243:26 | v1 | | -| vector.cpp:243:13:243:14 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | -| vector.cpp:243:25:243:26 | ref arg v1 | vector.cpp:268:1:268:1 | v1 | | -| vector.cpp:244:3:244:4 | ref arg v5 | vector.cpp:252:8:252:9 | v5 | | -| vector.cpp:244:3:244:4 | ref arg v5 | vector.cpp:256:2:256:2 | v5 | | -| vector.cpp:244:13:244:14 | ref arg v3 | vector.cpp:244:25:244:26 | v3 | | -| vector.cpp:244:13:244:14 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | -| vector.cpp:244:13:244:14 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | -| vector.cpp:244:25:244:26 | ref arg v3 | vector.cpp:245:8:245:9 | v3 | | -| vector.cpp:244:25:244:26 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | -| vector.cpp:245:8:245:9 | ref arg v3 | vector.cpp:268:1:268:1 | v3 | | -| vector.cpp:245:11:245:15 | call to begin | vector.cpp:245:3:245:17 | ... = ... | | -| vector.cpp:245:11:245:15 | call to begin | vector.cpp:246:3:246:4 | i1 | | -| vector.cpp:245:11:245:15 | call to begin | vector.cpp:247:8:247:9 | i1 | | -| vector.cpp:245:11:245:15 | call to begin | vector.cpp:249:13:249:14 | i1 | | -| vector.cpp:245:11:245:15 | call to begin | vector.cpp:253:8:253:9 | i1 | | -| vector.cpp:246:3:246:4 | ref arg i1 | vector.cpp:247:8:247:9 | i1 | | -| vector.cpp:246:3:246:4 | ref arg i1 | vector.cpp:249:13:249:14 | i1 | | -| vector.cpp:246:3:246:4 | ref arg i1 | vector.cpp:253:8:253:9 | i1 | | -| vector.cpp:247:8:247:9 | i1 | vector.cpp:247:3:247:9 | ... = ... | | -| vector.cpp:247:8:247:9 | i1 | vector.cpp:248:3:248:4 | i2 | | -| vector.cpp:247:8:247:9 | i1 | vector.cpp:249:17:249:18 | i2 | | -| vector.cpp:247:8:247:9 | i1 | vector.cpp:254:8:254:9 | i2 | | -| vector.cpp:248:3:248:4 | ref arg i2 | vector.cpp:249:17:249:18 | i2 | | -| vector.cpp:248:3:248:4 | ref arg i2 | vector.cpp:254:8:254:9 | i2 | | -| vector.cpp:249:3:249:4 | ref arg v6 | vector.cpp:255:8:255:9 | v6 | | -| vector.cpp:249:3:249:4 | ref arg v6 | vector.cpp:256:2:256:2 | v6 | | -| vector.cpp:251:8:251:9 | ref arg v4 | vector.cpp:256:2:256:2 | v4 | | -| vector.cpp:252:8:252:9 | ref arg v5 | vector.cpp:256:2:256:2 | v5 | | -| vector.cpp:255:8:255:9 | ref arg v6 | vector.cpp:256:2:256:2 | v6 | | -| vector.cpp:259:22:259:23 | call to vector | vector.cpp:262:3:262:4 | v7 | | -| vector.cpp:259:22:259:23 | call to vector | vector.cpp:265:8:265:9 | v7 | | -| vector.cpp:259:22:259:23 | call to vector | vector.cpp:267:2:267:2 | v7 | | -| vector.cpp:260:24:260:25 | call to vector | vector.cpp:263:3:263:4 | v8 | | -| vector.cpp:260:24:260:25 | call to vector | vector.cpp:266:8:266:9 | v8 | | -| vector.cpp:260:24:260:25 | call to vector | vector.cpp:267:2:267:2 | v8 | | -| vector.cpp:262:3:262:4 | ref arg v7 | vector.cpp:265:8:265:9 | v7 | | -| vector.cpp:262:3:262:4 | ref arg v7 | vector.cpp:267:2:267:2 | v7 | | -| vector.cpp:262:13:262:15 | 100 | vector.cpp:262:3:262:4 | ref arg v7 | TAINT | -| vector.cpp:262:18:262:31 | call to source | vector.cpp:262:3:262:4 | ref arg v7 | TAINT | -| vector.cpp:263:3:263:4 | ref arg v8 | vector.cpp:266:8:266:9 | v8 | | -| vector.cpp:263:3:263:4 | ref arg v8 | vector.cpp:267:2:267:2 | v8 | | -| vector.cpp:263:18:263:35 | call to source | vector.cpp:263:3:263:4 | ref arg v8 | TAINT | -| vector.cpp:265:8:265:9 | ref arg v7 | vector.cpp:267:2:267:2 | v7 | | -| vector.cpp:266:8:266:9 | ref arg v8 | vector.cpp:267:2:267:2 | v8 | | -| vector.cpp:273:19:273:20 | call to vector | vector.cpp:275:2:275:3 | v1 | | -| vector.cpp:273:19:273:20 | call to vector | vector.cpp:276:7:276:8 | v1 | | -| vector.cpp:273:19:273:20 | call to vector | vector.cpp:277:7:277:8 | v1 | | -| vector.cpp:273:19:273:20 | call to vector | vector.cpp:278:7:278:8 | v1 | | -| vector.cpp:273:19:273:20 | call to vector | vector.cpp:284:1:284:1 | v1 | | -| vector.cpp:273:23:273:24 | call to vector | vector.cpp:280:4:280:5 | v2 | | -| vector.cpp:273:23:273:24 | call to vector | vector.cpp:281:7:281:8 | v2 | | -| vector.cpp:273:23:273:24 | call to vector | vector.cpp:282:7:282:8 | v2 | | -| vector.cpp:273:23:273:24 | call to vector | vector.cpp:283:7:283:8 | v2 | | -| vector.cpp:273:23:273:24 | call to vector | vector.cpp:284:1:284:1 | v2 | | -| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:276:7:276:8 | v1 | | -| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:277:7:277:8 | v1 | | -| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:278:7:278:8 | v1 | | -| vector.cpp:275:2:275:3 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | -| vector.cpp:275:15:275:20 | call to source | vector.cpp:275:2:275:3 | ref arg v1 | TAINT | -| vector.cpp:276:7:276:8 | ref arg v1 | vector.cpp:277:7:277:8 | v1 | | -| vector.cpp:276:7:276:8 | ref arg v1 | vector.cpp:278:7:278:8 | v1 | | -| vector.cpp:276:7:276:8 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | -| vector.cpp:277:7:277:8 | ref arg v1 | vector.cpp:278:7:278:8 | v1 | | -| vector.cpp:277:7:277:8 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | -| vector.cpp:277:7:277:8 | v1 | vector.cpp:277:10:277:13 | call to data | TAINT | -| vector.cpp:277:10:277:13 | ref arg call to data | vector.cpp:277:7:277:8 | ref arg v1 | TAINT | -| vector.cpp:278:7:278:8 | ref arg v1 | vector.cpp:284:1:284:1 | v1 | | -| vector.cpp:278:7:278:8 | v1 | vector.cpp:278:10:278:13 | call to data | TAINT | -| vector.cpp:278:10:278:13 | call to data | vector.cpp:278:7:278:18 | access to array | TAINT | -| vector.cpp:278:17:278:17 | 2 | vector.cpp:278:7:278:18 | access to array | TAINT | -| vector.cpp:280:2:280:13 | * ... [post update] | vector.cpp:280:7:280:10 | call to data [inner post update] | | -| vector.cpp:280:2:280:32 | ... = ... | vector.cpp:280:2:280:13 | * ... [post update] | | -| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:281:7:281:8 | v2 | | -| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:282:7:282:8 | v2 | | -| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:283:7:283:8 | v2 | | -| vector.cpp:280:4:280:5 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | -| vector.cpp:280:4:280:5 | v2 | vector.cpp:280:7:280:10 | call to data | TAINT | -| vector.cpp:280:7:280:10 | call to data | vector.cpp:280:2:280:13 | * ... | TAINT | -| vector.cpp:280:7:280:10 | call to data [inner post update] | vector.cpp:280:4:280:5 | ref arg v2 | TAINT | -| vector.cpp:280:17:280:30 | call to source | vector.cpp:280:2:280:32 | ... = ... | | -| vector.cpp:281:7:281:8 | ref arg v2 | vector.cpp:282:7:282:8 | v2 | | -| vector.cpp:281:7:281:8 | ref arg v2 | vector.cpp:283:7:283:8 | v2 | | -| vector.cpp:281:7:281:8 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | -| vector.cpp:282:7:282:8 | ref arg v2 | vector.cpp:283:7:283:8 | v2 | | -| vector.cpp:282:7:282:8 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | -| vector.cpp:282:7:282:8 | v2 | vector.cpp:282:10:282:13 | call to data | TAINT | -| vector.cpp:282:10:282:13 | ref arg call to data | vector.cpp:282:7:282:8 | ref arg v2 | TAINT | -| vector.cpp:283:7:283:8 | ref arg v2 | vector.cpp:284:1:284:1 | v2 | | -| vector.cpp:283:7:283:8 | v2 | vector.cpp:283:10:283:13 | call to data | TAINT | -| vector.cpp:283:10:283:13 | call to data | vector.cpp:283:7:283:18 | access to array | TAINT | -| vector.cpp:283:17:283:17 | 2 | vector.cpp:283:7:283:18 | access to array | TAINT | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:237:2:237:3 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:241:7:241:8 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:249:13:249:14 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:235:19:235:20 | call to vector | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:235:23:235:24 | call to vector | vector.cpp:238:2:238:3 | v2 | | +| vector.cpp:235:23:235:24 | call to vector | vector.cpp:242:7:242:8 | v2 | | +| vector.cpp:235:23:235:24 | call to vector | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:239:2:239:3 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:243:7:243:8 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:250:13:250:14 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:235:27:235:28 | call to vector | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:241:7:241:8 | v1 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:13:249:14 | v1 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:237:12:237:14 | 100 | vector.cpp:237:2:237:3 | ref arg v1 | TAINT | +| vector.cpp:237:17:237:17 | 0 | vector.cpp:237:2:237:3 | ref arg v1 | TAINT | +| vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:242:7:242:8 | v2 | | +| vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:238:12:238:14 | 100 | vector.cpp:238:2:238:3 | ref arg v2 | TAINT | +| vector.cpp:238:17:238:30 | call to source | vector.cpp:238:2:238:3 | ref arg v2 | TAINT | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:243:7:243:8 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:13:250:14 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:239:15:239:20 | call to source | vector.cpp:239:2:239:3 | ref arg v3 | TAINT | +| vector.cpp:241:7:241:8 | ref arg v1 | vector.cpp:249:13:249:14 | v1 | | +| vector.cpp:241:7:241:8 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:241:7:241:8 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:242:7:242:8 | ref arg v2 | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:250:13:250:14 | v3 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:243:7:243:8 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:246:20:246:21 | call to vector | vector.cpp:249:3:249:4 | v4 | | +| vector.cpp:246:20:246:21 | call to vector | vector.cpp:257:8:257:9 | v4 | | +| vector.cpp:246:20:246:21 | call to vector | vector.cpp:262:2:262:2 | v4 | | +| vector.cpp:246:24:246:25 | call to vector | vector.cpp:250:3:250:4 | v5 | | +| vector.cpp:246:24:246:25 | call to vector | vector.cpp:258:8:258:9 | v5 | | +| vector.cpp:246:24:246:25 | call to vector | vector.cpp:262:2:262:2 | v5 | | +| vector.cpp:246:28:246:29 | call to vector | vector.cpp:255:3:255:4 | v6 | | +| vector.cpp:246:28:246:29 | call to vector | vector.cpp:261:8:261:9 | v6 | | +| vector.cpp:246:28:246:29 | call to vector | vector.cpp:262:2:262:2 | v6 | | +| vector.cpp:249:3:249:4 | ref arg v4 | vector.cpp:257:8:257:9 | v4 | | +| vector.cpp:249:3:249:4 | ref arg v4 | vector.cpp:262:2:262:2 | v4 | | +| vector.cpp:249:13:249:14 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | +| vector.cpp:249:13:249:14 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:249:25:249:26 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:250:3:250:4 | ref arg v5 | vector.cpp:258:8:258:9 | v5 | | +| vector.cpp:250:3:250:4 | ref arg v5 | vector.cpp:262:2:262:2 | v5 | | +| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | +| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:250:13:250:14 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:250:25:250:26 | ref arg v3 | vector.cpp:251:8:251:9 | v3 | | +| vector.cpp:250:25:250:26 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:251:8:251:9 | ref arg v3 | vector.cpp:277:1:277:1 | v3 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:251:3:251:17 | ... = ... | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:252:3:252:4 | i1 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:253:8:253:9 | i1 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:255:13:255:14 | i1 | | +| vector.cpp:251:11:251:15 | call to begin | vector.cpp:259:8:259:9 | i1 | | +| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:253:8:253:9 | i1 | | +| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:255:13:255:14 | i1 | | +| vector.cpp:252:3:252:4 | ref arg i1 | vector.cpp:259:8:259:9 | i1 | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:253:3:253:9 | ... = ... | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:254:3:254:4 | i2 | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:255:17:255:18 | i2 | | +| vector.cpp:253:8:253:9 | i1 | vector.cpp:260:8:260:9 | i2 | | +| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:255:17:255:18 | i2 | | +| vector.cpp:254:3:254:4 | ref arg i2 | vector.cpp:260:8:260:9 | i2 | | +| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:261:8:261:9 | v6 | | +| vector.cpp:255:3:255:4 | ref arg v6 | vector.cpp:262:2:262:2 | v6 | | +| vector.cpp:257:8:257:9 | ref arg v4 | vector.cpp:262:2:262:2 | v4 | | +| vector.cpp:258:8:258:9 | ref arg v5 | vector.cpp:262:2:262:2 | v5 | | +| vector.cpp:261:8:261:9 | ref arg v6 | vector.cpp:262:2:262:2 | v6 | | +| vector.cpp:265:22:265:23 | call to vector | vector.cpp:269:3:269:4 | v7 | | +| vector.cpp:265:22:265:23 | call to vector | vector.cpp:273:8:273:9 | v7 | | +| vector.cpp:265:22:265:23 | call to vector | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:266:24:266:25 | call to vector | vector.cpp:270:3:270:4 | v8 | | +| vector.cpp:266:24:266:25 | call to vector | vector.cpp:274:8:274:9 | v8 | | +| vector.cpp:266:24:266:25 | call to vector | vector.cpp:276:2:276:2 | v8 | | +| vector.cpp:267:28:267:29 | call to vector | vector.cpp:271:3:271:4 | v9 | | +| vector.cpp:267:28:267:29 | call to vector | vector.cpp:275:8:275:9 | v9 | | +| vector.cpp:267:28:267:29 | call to vector | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:273:8:273:9 | v7 | | +| vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:269:13:269:15 | 100 | vector.cpp:269:3:269:4 | ref arg v7 | TAINT | +| vector.cpp:269:18:269:31 | call to source | vector.cpp:269:3:269:4 | ref arg v7 | TAINT | +| vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:274:8:274:9 | v8 | | +| vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | +| vector.cpp:270:18:270:35 | call to source | vector.cpp:270:3:270:4 | ref arg v8 | TAINT | +| vector.cpp:271:3:271:4 | ref arg v9 | vector.cpp:275:8:275:9 | v9 | | +| vector.cpp:271:3:271:4 | ref arg v9 | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:273:8:273:9 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:274:8:274:9 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | +| vector.cpp:275:8:275:9 | ref arg v9 | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:284:2:284:3 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:285:7:285:8 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:286:7:286:8 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:282:19:282:20 | call to vector | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:289:4:289:5 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:290:7:290:8 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:291:7:291:8 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:282:23:282:24 | call to vector | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:285:7:285:8 | v1 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:286:7:286:8 | v1 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:284:2:284:3 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:284:15:284:20 | call to source | vector.cpp:284:2:284:3 | ref arg v1 | TAINT | +| vector.cpp:285:7:285:8 | ref arg v1 | vector.cpp:286:7:286:8 | v1 | | +| vector.cpp:285:7:285:8 | ref arg v1 | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:285:7:285:8 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:286:7:286:8 | ref arg v1 | vector.cpp:287:7:287:8 | v1 | | +| vector.cpp:286:7:286:8 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:286:7:286:8 | v1 | vector.cpp:286:10:286:13 | call to data | TAINT | +| vector.cpp:286:10:286:13 | ref arg call to data | vector.cpp:286:7:286:8 | ref arg v1 | TAINT | +| vector.cpp:287:7:287:8 | ref arg v1 | vector.cpp:293:1:293:1 | v1 | | +| vector.cpp:287:7:287:8 | v1 | vector.cpp:287:10:287:13 | call to data | TAINT | +| vector.cpp:287:10:287:13 | call to data | vector.cpp:287:7:287:18 | access to array | TAINT | +| vector.cpp:287:17:287:17 | 2 | vector.cpp:287:7:287:18 | access to array | TAINT | +| vector.cpp:289:2:289:13 | * ... [post update] | vector.cpp:289:7:289:10 | call to data [inner post update] | | +| vector.cpp:289:2:289:32 | ... = ... | vector.cpp:289:2:289:13 | * ... [post update] | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:290:7:290:8 | v2 | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:291:7:291:8 | v2 | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:289:4:289:5 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:289:4:289:5 | v2 | vector.cpp:289:7:289:10 | call to data | TAINT | +| vector.cpp:289:7:289:10 | call to data | vector.cpp:289:2:289:13 | * ... | TAINT | +| vector.cpp:289:7:289:10 | call to data [inner post update] | vector.cpp:289:4:289:5 | ref arg v2 | TAINT | +| vector.cpp:289:17:289:30 | call to source | vector.cpp:289:2:289:32 | ... = ... | | +| vector.cpp:290:7:290:8 | ref arg v2 | vector.cpp:291:7:291:8 | v2 | | +| vector.cpp:290:7:290:8 | ref arg v2 | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:290:7:290:8 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:291:7:291:8 | ref arg v2 | vector.cpp:292:7:292:8 | v2 | | +| vector.cpp:291:7:291:8 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:291:7:291:8 | v2 | vector.cpp:291:10:291:13 | call to data | TAINT | +| vector.cpp:291:10:291:13 | ref arg call to data | vector.cpp:291:7:291:8 | ref arg v2 | TAINT | +| vector.cpp:292:7:292:8 | ref arg v2 | vector.cpp:293:1:293:1 | v2 | | +| vector.cpp:292:7:292:8 | v2 | vector.cpp:292:10:292:13 | call to data | TAINT | +| vector.cpp:292:10:292:13 | call to data | vector.cpp:292:7:292:18 | access to array | TAINT | +| vector.cpp:292:17:292:17 | 2 | vector.cpp:292:7:292:18 | access to array | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index c82a1134c7f..ed193182043 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -241,13 +241,13 @@ | vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | | vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | -| vector.cpp:236:7:236:8 | v2 | vector.cpp:232:17:232:30 | call to source | -| vector.cpp:237:7:237:8 | v3 | vector.cpp:233:15:233:20 | call to source | -| vector.cpp:265:8:265:9 | v7 | vector.cpp:262:18:262:31 | call to source | -| vector.cpp:266:8:266:9 | v8 | vector.cpp:263:18:263:35 | call to source | -| vector.cpp:276:7:276:8 | v1 | vector.cpp:275:15:275:20 | call to source | -| vector.cpp:277:10:277:13 | call to data | vector.cpp:275:15:275:20 | call to source | -| vector.cpp:278:7:278:18 | access to array | vector.cpp:275:15:275:20 | call to source | -| vector.cpp:281:7:281:8 | v2 | vector.cpp:280:17:280:30 | call to source | -| vector.cpp:282:10:282:13 | call to data | vector.cpp:280:17:280:30 | call to source | -| vector.cpp:283:7:283:18 | access to array | vector.cpp:280:17:280:30 | call to source | +| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source | +| vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source | +| vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source | +| vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:286:10:286:13 | call to data | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:287:7:287:18 | access to array | vector.cpp:284:15:284:20 | call to source | +| vector.cpp:290:7:290:8 | v2 | vector.cpp:289:17:289:30 | call to source | +| vector.cpp:291:10:291:13 | call to data | vector.cpp:289:17:289:30 | call to source | +| vector.cpp:292:7:292:18 | access to array | vector.cpp:289:17:289:30 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index e909d08e97e..c92595c49ab 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -177,13 +177,13 @@ | vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | | vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | -| vector.cpp:236:7:236:8 | vector.cpp:232:17:232:30 | AST only | -| vector.cpp:237:7:237:8 | vector.cpp:233:15:233:20 | AST only | -| vector.cpp:265:8:265:9 | vector.cpp:262:18:262:31 | AST only | -| vector.cpp:266:8:266:9 | vector.cpp:263:18:263:35 | AST only | -| vector.cpp:276:7:276:8 | vector.cpp:275:15:275:20 | AST only | -| vector.cpp:277:10:277:13 | vector.cpp:275:15:275:20 | AST only | -| vector.cpp:278:7:278:18 | vector.cpp:275:15:275:20 | AST only | -| vector.cpp:281:7:281:8 | vector.cpp:280:17:280:30 | AST only | -| vector.cpp:282:10:282:13 | vector.cpp:280:17:280:30 | AST only | -| vector.cpp:283:7:283:18 | vector.cpp:280:17:280:30 | AST only | +| vector.cpp:242:7:242:8 | vector.cpp:238:17:238:30 | AST only | +| vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only | +| vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only | +| vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only | +| vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only | +| vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only | +| vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only | +| vector.cpp:290:7:290:8 | vector.cpp:289:17:289:30 | AST only | +| vector.cpp:291:10:291:13 | vector.cpp:289:17:289:30 | AST only | +| vector.cpp:292:7:292:18 | vector.cpp:289:17:289:30 | AST only | 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 bb1c6ef5dcf..1105ad12f96 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -223,7 +223,13 @@ namespace ns_myFloat myFloat source(); } +namespace ns_ci_ptr +{ + const int *source(); +} + void sink(std::vector &); +void sink(std::vector &); void test_vector_assign() { std::vector v1, v2, v3; @@ -258,12 +264,15 @@ void test_vector_assign() { { std::vector v7; std::vector v8; + std::vector v9; v7.assign(100, ns_int::source()); v8.assign(100, ns_myFloat::source()); + v9.assign(100, ns_ci_ptr::source()); sink(v7); // tainted sink(v8); // tainted + sink(v9); // tainted [NOT DETECTED] } } From 865d91de805e00337751903dec7167bd3aa8b7ef Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:04:00 +0100 Subject: [PATCH 129/146] C++: Fix getAValueTypeParameterIndex(). --- .../semmle/code/cpp/models/implementations/StdContainer.qll | 4 ++-- .../library-tests/dataflow/taint-tests/localTaint.expected | 1 + cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected | 1 + .../library-tests/dataflow/taint-tests/test_diff.expected | 1 + cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp | 2 +- 5 files changed, 6 insertions(+), 3 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 bee2ab4974c..ac5b8e55485 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -101,10 +101,10 @@ class StdSequenceContainerAssign extends TaintFunction { * value type of the container. */ int getAValueTypeParameterIndex() { - getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0) // i.e. the `T` of this `std::vector` + getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` or getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(0) + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() } override predicate hasTaintFlow(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 198c1e914ba..36f2638b451 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -2325,6 +2325,7 @@ | vector.cpp:270:18:270:35 | call to source | vector.cpp:270:3:270:4 | ref arg v8 | TAINT | | vector.cpp:271:3:271:4 | ref arg v9 | vector.cpp:275:8:275:9 | v9 | | | vector.cpp:271:3:271:4 | ref arg v9 | vector.cpp:276:2:276:2 | v9 | | +| vector.cpp:271:18:271:34 | call to source | vector.cpp:271:3:271:4 | ref arg v9 | TAINT | | vector.cpp:273:8:273:9 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | | vector.cpp:274:8:274:9 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | | vector.cpp:275:8:275:9 | ref arg v9 | vector.cpp:276:2:276:2 | v9 | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index ed193182043..df1c8c21210 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -245,6 +245,7 @@ | vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source | | vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source | | vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source | +| vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source | | vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source | | vector.cpp:286:10:286:13 | call to data | vector.cpp:284:15:284:20 | call to source | | vector.cpp:287:7:287:18 | access to array | vector.cpp:284:15:284:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index c92595c49ab..b312fb0b71b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -181,6 +181,7 @@ | vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only | | vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only | | vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only | +| vector.cpp:275:8:275:9 | vector.cpp:271:18:271:34 | AST only | | vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only | | vector.cpp:286:10:286:13 | vector.cpp:284:15:284:20 | AST only | | vector.cpp:287:7:287:18 | vector.cpp:284:15:284:20 | AST only | 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 1105ad12f96..9c295fbe541 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/vector.cpp @@ -272,7 +272,7 @@ void test_vector_assign() { sink(v7); // tainted sink(v8); // tainted - sink(v9); // tainted [NOT DETECTED] + sink(v9); // tainted } } From 071b303ea06e13cb00751bec080a05670531dc03 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:17:04 +0100 Subject: [PATCH 130/146] C++: Make the other versions consistent with this. --- .../code/cpp/models/implementations/StdContainer.qll | 2 +- .../code/cpp/models/implementations/StdString.qll | 12 ++++++------ 2 files changed, 7 insertions(+), 7 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 ac5b8e55485..6091f9f6395 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -23,7 +23,7 @@ class StdSequenceContainerConstructor extends Constructor, TaintFunction { */ int getAValueTypeParameterIndex() { getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(0) // i.e. the `T` of this `std::vector` + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` } 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 7ed73e59a21..2910f068be9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -71,17 +71,17 @@ class StdStringAppend extends TaintFunction { * Gets the index of a parameter to this function that is a string (or * character). */ - int getAStringParameter() { + int getAStringParameterIndex() { getParameter(result).getType() instanceof PointerType or getParameter(result).getType() instanceof ReferenceType or - getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT` + getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from string and parameter to string (qualifier) and return value ( input.isQualifierObject() or - input.isParameterDeref(getAStringParameter()) + input.isParameterDeref(getAStringParameterIndex()) ) and ( output.isQualifierObject() or @@ -100,15 +100,15 @@ class StdStringAssign extends TaintFunction { * Gets the index of a parameter to this function that is a string (or * character). */ - int getAStringParameter() { + int getAStringParameterIndex() { getParameter(result).getType() instanceof PointerType or getParameter(result).getType() instanceof ReferenceType or - getParameter(result).getType() = getDeclaringType().getTemplateArgument(0) // i.e. `std::basic_string::CharT` + getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { // flow from parameter to string itself (qualifier) and return value - input.isParameterDeref(getAStringParameter()) and + input.isParameterDeref(getAStringParameterIndex()) and ( output.isQualifierObject() or output.isReturnValueDeref() From 927a4faa5829f52b96b4637cc30a7acf3c6c36cd Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:40:07 +0100 Subject: [PATCH 131/146] C++: Remove the non-reference case that we shouldn't need. --- .../semmle/code/cpp/models/implementations/StdContainer.qll | 4 +--- .../library-tests/dataflow/taint-tests/localTaint.expected | 6 ------ .../test/library-tests/dataflow/taint-tests/taint.expected | 2 -- .../library-tests/dataflow/taint-tests/test_diff.expected | 2 -- 4 files changed, 1 insertion(+), 13 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 6091f9f6395..06daa9126d1 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdContainer.qll @@ -101,10 +101,8 @@ class StdSequenceContainerAssign extends TaintFunction { * value type of the container. */ int getAValueTypeParameterIndex() { - getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` - or getParameter(result).getUnspecifiedType().(ReferenceType).getBaseType() = - getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. the `T` of this `std::vector` } override predicate hasTaintFlow(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 36f2638b451..ebd0beddf0d 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -2246,12 +2246,8 @@ | vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:13:249:14 | v1 | | | vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | | vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | -| vector.cpp:237:12:237:14 | 100 | vector.cpp:237:2:237:3 | ref arg v1 | TAINT | -| vector.cpp:237:17:237:17 | 0 | vector.cpp:237:2:237:3 | ref arg v1 | TAINT | | vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:242:7:242:8 | v2 | | | vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:277:1:277:1 | v2 | | -| vector.cpp:238:12:238:14 | 100 | vector.cpp:238:2:238:3 | ref arg v2 | TAINT | -| vector.cpp:238:17:238:30 | call to source | vector.cpp:238:2:238:3 | ref arg v2 | TAINT | | vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:243:7:243:8 | v3 | | | vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:13:250:14 | v3 | | | vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | @@ -2318,8 +2314,6 @@ | vector.cpp:267:28:267:29 | call to vector | vector.cpp:276:2:276:2 | v9 | | | vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:273:8:273:9 | v7 | | | vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | -| vector.cpp:269:13:269:15 | 100 | vector.cpp:269:3:269:4 | ref arg v7 | TAINT | -| vector.cpp:269:18:269:31 | call to source | vector.cpp:269:3:269:4 | ref arg v7 | TAINT | | vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:274:8:274:9 | v8 | | | vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | | vector.cpp:270:18:270:35 | call to source | vector.cpp:270:3:270:4 | ref arg v8 | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index df1c8c21210..ae9d740e3f0 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -241,9 +241,7 @@ | vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | | vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | -| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source | | vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source | -| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source | | vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source | | vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source | | vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index b312fb0b71b..51ceb9e46c2 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -177,9 +177,7 @@ | vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | | vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | -| vector.cpp:242:7:242:8 | vector.cpp:238:17:238:30 | AST only | | vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only | -| vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only | | vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only | | vector.cpp:275:8:275:9 | vector.cpp:271:18:271:34 | AST only | | vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only | From e7a0bc6be68d9d436201c5edf6153c314037ddf3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Thu, 27 Aug 2020 15:48:15 +0100 Subject: [PATCH 132/146] JS: Lower precision of ambiguous HTML ID attribute --- change-notes/1.26/analysis-javascript.md | 1 + javascript/config/suites/javascript/correctness-core | 1 - javascript/ql/src/DOM/AmbiguousIdAttribute.ql | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/change-notes/1.26/analysis-javascript.md b/change-notes/1.26/analysis-javascript.md index 3c1f05c4fbb..afa97ca0ed6 100644 --- a/change-notes/1.26/analysis-javascript.md +++ b/change-notes/1.26/analysis-javascript.md @@ -27,6 +27,7 @@ | **Query** | **Expected impact** | **Change** | |--------------------------------|------------------------------|---------------------------------------------------------------------------| | Incomplete URL substring sanitization (`js/incomplete-url-substring-sanitization`) | More results | This query now recognizes additional URLs when the substring check is an inclusion check. | +| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Results no longer shown | Precision tag reduced to "low". The query is no longer run by default. | ## Changes to libraries diff --git a/javascript/config/suites/javascript/correctness-core b/javascript/config/suites/javascript/correctness-core index 59117aa390c..6baa782a5b2 100644 --- a/javascript/config/suites/javascript/correctness-core +++ b/javascript/config/suites/javascript/correctness-core @@ -7,7 +7,6 @@ + semmlecode-javascript-queries/Declarations/UniqueParameterNames.ql: /Correctness/Declarations + semmlecode-javascript-queries/Declarations/UniquePropertyNames.ql: /Correctness/Declarations + semmlecode-javascript-queries/Declarations/IneffectiveParameterType.ql: /Correctness/Declarations -+ semmlecode-javascript-queries/DOM/AmbiguousIdAttribute.ql: /Correctness/DOM + semmlecode-javascript-queries/DOM/ConflictingAttributes.ql: /Correctness/DOM + semmlecode-javascript-queries/DOM/MalformedIdAttribute.ql: /Correctness/DOM + semmlecode-javascript-queries/Expressions/ComparisonWithNaN.ql: /Correctness/Expressions diff --git a/javascript/ql/src/DOM/AmbiguousIdAttribute.ql b/javascript/ql/src/DOM/AmbiguousIdAttribute.ql index 3680f86ab72..b6647a2ea13 100644 --- a/javascript/ql/src/DOM/AmbiguousIdAttribute.ql +++ b/javascript/ql/src/DOM/AmbiguousIdAttribute.ql @@ -8,7 +8,7 @@ * @id js/duplicate-html-id * @tags maintainability * correctness - * @precision high + * @precision low */ import javascript From 208cd4c888bf262279c38a50134dbf0a63f9b850 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 15:54:27 +0100 Subject: [PATCH 133/146] C++: Fix assign in the test stl.h. --- .../dataflow/taint-tests/localTaint.expected | 15 +++++++++------ .../test/library-tests/dataflow/taint-tests/stl.h | 8 ++++++-- .../dataflow/taint-tests/taint.expected | 2 ++ .../dataflow/taint-tests/test_diff.expected | 2 ++ 4 files changed, 19 insertions(+), 8 deletions(-) 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 ebd0beddf0d..7ac47152937 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -313,12 +313,12 @@ | movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT | | movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT | | movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT | -| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | -| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | -| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | -| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | -| stl.h:137:30:137:40 | call to allocator | stl.h:137:21:137:41 | noexcept(...) | TAINT | -| stl.h:137:53:137:63 | 0 | stl.h:137:46:137:64 | (no string representation) | TAINT | +| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT | +| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT | +| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT | +| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT | +| stl.h:139:30:139:40 | call to allocator | stl.h:139:21:139:41 | noexcept(...) | TAINT | +| stl.h:139:53:139:63 | 0 | stl.h:139:46:139:64 | (no string representation) | TAINT | | string.cpp:24:12:24:17 | call to source | string.cpp:28:7:28:7 | a | | | string.cpp:25:16:25:20 | 123 | string.cpp:25:16:25:21 | call to basic_string | TAINT | | string.cpp:25:16:25:21 | call to basic_string | string.cpp:29:7:29:7 | b | | @@ -2246,8 +2246,10 @@ | vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:13:249:14 | v1 | | | vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:249:25:249:26 | v1 | | | vector.cpp:237:2:237:3 | ref arg v1 | vector.cpp:277:1:277:1 | v1 | | +| vector.cpp:237:17:237:17 | 0 | vector.cpp:237:2:237:3 | ref arg v1 | TAINT | | vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:242:7:242:8 | v2 | | | vector.cpp:238:2:238:3 | ref arg v2 | vector.cpp:277:1:277:1 | v2 | | +| vector.cpp:238:17:238:30 | call to source | vector.cpp:238:2:238:3 | ref arg v2 | TAINT | | vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:243:7:243:8 | v3 | | | vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:13:250:14 | v3 | | | vector.cpp:239:2:239:3 | ref arg v3 | vector.cpp:250:25:250:26 | v3 | | @@ -2314,6 +2316,7 @@ | vector.cpp:267:28:267:29 | call to vector | vector.cpp:276:2:276:2 | v9 | | | vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:273:8:273:9 | v7 | | | vector.cpp:269:3:269:4 | ref arg v7 | vector.cpp:276:2:276:2 | v7 | | +| vector.cpp:269:18:269:31 | call to source | vector.cpp:269:3:269:4 | ref arg v7 | TAINT | | vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:274:8:274:9 | v8 | | | vector.cpp:270:3:270:4 | ref arg v8 | vector.cpp:276:2:276:2 | v8 | | | vector.cpp:270:18:270:35 | call to source | vector.cpp:270:3:270:4 | ref arg v8 | TAINT | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h index 77df0e91f99..e9a27670c2f 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/stl.h @@ -11,12 +11,14 @@ namespace std struct ptrdiff_t; - template struct iterator { + typedef Category iterator_category; + iterator &operator++(); iterator operator++(int); bool operator==(iterator other) const; @@ -142,7 +144,9 @@ namespace std { vector& operator=(const vector& x); vector& operator=(vector&& x) noexcept/*(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value)*/; - template void assign(InputIterator first, InputIterator last); + template void assign(InputIterator first, InputIterator last); + // use of `iterator_category` makes sure InputIterator is (probably) an iterator, and not an `int` or + // similar that should match a different overload (SFINAE). void assign(size_type n, const T& u); iterator begin() noexcept; diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected index ae9d740e3f0..df1c8c21210 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected @@ -241,7 +241,9 @@ | vector.cpp:171:13:171:13 | call to operator[] | vector.cpp:170:14:170:19 | call to source | | vector.cpp:180:13:180:13 | call to operator[] | vector.cpp:179:14:179:19 | call to source | | vector.cpp:201:13:201:13 | call to operator[] | vector.cpp:200:14:200:19 | call to source | +| vector.cpp:242:7:242:8 | v2 | vector.cpp:238:17:238:30 | call to source | | vector.cpp:243:7:243:8 | v3 | vector.cpp:239:15:239:20 | call to source | +| vector.cpp:273:8:273:9 | v7 | vector.cpp:269:18:269:31 | call to source | | vector.cpp:274:8:274:9 | v8 | vector.cpp:270:18:270:35 | call to source | | vector.cpp:275:8:275:9 | v9 | vector.cpp:271:18:271:34 | call to source | | vector.cpp:285:7:285:8 | v1 | vector.cpp:284:15:284:20 | call to source | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected index 51ceb9e46c2..b312fb0b71b 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected @@ -177,7 +177,9 @@ | vector.cpp:171:13:171:13 | vector.cpp:170:14:170:19 | AST only | | vector.cpp:180:13:180:13 | vector.cpp:179:14:179:19 | AST only | | vector.cpp:201:13:201:13 | vector.cpp:200:14:200:19 | AST only | +| vector.cpp:242:7:242:8 | vector.cpp:238:17:238:30 | AST only | | vector.cpp:243:7:243:8 | vector.cpp:239:15:239:20 | AST only | +| vector.cpp:273:8:273:9 | vector.cpp:269:18:269:31 | AST only | | vector.cpp:274:8:274:9 | vector.cpp:270:18:270:35 | AST only | | vector.cpp:275:8:275:9 | vector.cpp:271:18:271:34 | AST only | | vector.cpp:285:7:285:8 | vector.cpp:284:15:284:20 | AST only | From 9b3da1f6c79ca1a614e1af9615d5aa5cfd02bd96 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 27 Aug 2020 16:55:45 +0100 Subject: [PATCH 134/146] C++: Autoformat. --- .../semmle/code/cpp/models/implementations/StdString.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 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 2910f068be9..56151e8043e 100644 --- a/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/StdString.qll @@ -74,7 +74,8 @@ class StdStringAppend extends TaintFunction { int getAStringParameterIndex() { getParameter(result).getType() instanceof PointerType or getParameter(result).getType() instanceof ReferenceType or - getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + getParameter(result).getUnspecifiedType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { @@ -103,7 +104,8 @@ class StdStringAssign extends TaintFunction { int getAStringParameterIndex() { getParameter(result).getType() instanceof PointerType or getParameter(result).getType() instanceof ReferenceType or - getParameter(result).getUnspecifiedType() = getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` + getParameter(result).getUnspecifiedType() = + getDeclaringType().getTemplateArgument(0).(Type).getUnspecifiedType() // i.e. `std::basic_string::CharT` } override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { From 29eaacdeaf720fad0e87c9019959ac7bbe1b014e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 28 Aug 2020 08:39:16 +0200 Subject: [PATCH 135/146] Fix typos and comment styling --- csharp/ql/src/Linq/Helpers.qll | 38 ++++++++++--------- csharp/ql/src/external/CodeDuplication.qll | 2 +- csharp/ql/src/semmle/code/cil/Access.qll | 2 +- .../ql/src/semmle/code/csharp/exprs/Expr.qll | 2 +- .../csharp/frameworks/EntityFramework.qll | 7 +++- .../code/csharp/frameworks/system/Linq.qll | 2 +- .../csharp/frameworks/system/data/Common.qll | 2 +- .../csharp/frameworks/system/data/Entity.qll | 4 +- .../frameworks/system/linq/Expressions.qll | 2 +- .../csharp/frameworks/system/xml/XPath.qll | 2 +- .../semmle/code/csharp/metrics/Coupling.qll | 4 +- .../csharp/serialization/Deserializers.qll | 12 ++---- 12 files changed, 40 insertions(+), 39 deletions(-) diff --git a/csharp/ql/src/Linq/Helpers.qll b/csharp/ql/src/Linq/Helpers.qll index fe50ca11396..41d1e305ca6 100644 --- a/csharp/ql/src/Linq/Helpers.qll +++ b/csharp/ql/src/Linq/Helpers.qll @@ -27,10 +27,10 @@ predicate isIEnumerableType(ValueOrRefType t) { } /** - * Holds if `ForeachStmt` could be converted to a `.All()` call. That is, - * the `ForeachStmt` contains a single `if` with a condition that accesses - * the loop variable and with a body that assigns `false` to a variable and - * `break`s out of the `foreach`. + * Holds if `foreach` statement `fes` could be converted to a `.All()` call. + * That is, the `ForeachStmt` contains a single `if` with a condition that + * accesses the loop variable and with a body that assigns `false` to a variable + * and `break`s out of the `foreach`. */ predicate missedAllOpportunity(ForeachStmt fes) { exists(IfStmt is | @@ -51,9 +51,10 @@ predicate missedAllOpportunity(ForeachStmt fes) { } /** - * Holds if `ForeachStmt` could be converted to a `.Cast()` call. That is, the - * loop variable is accessed only in the first statement of the block, and the - * access is a cast. The first statement needs to be a `LocalVariableDeclStmt`. + * Holds if `foreach` statement `fes` could be converted to a `.Cast()` call. + * That is, the loop variable is accessed only in the first statement of the + * block, and the access is a cast. The first statement needs to be a + * `LocalVariableDeclStmt`. */ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and @@ -67,10 +68,10 @@ predicate missedCastOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { } /** - * Holds if `ForeachStmt` could be converted to an `.OfType()` call. That is, the - * loop variable is accessed only in the first statement of the block, and the - * access is a cast with the `as` operator. The first statement needs to be a - * `LocalVariableDeclStmt`. + * Holds if `foreach` statement `fes` could be converted to an `.OfType()` call. + * That is, the loop variable is accessed only in the first statement of the + * block, and the access is a cast with the `as` operator. The first statement + * needs to be a `LocalVariableDeclStmt`. */ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and @@ -84,9 +85,10 @@ predicate missedOfTypeOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { } /** - * Holds if `ForeachStmt` could be converted to a `.Select()` call. That is, the - * loop variable is accessed only in the first statement of the block, and the - * access is not a cast. The first statement needs to be a `LocalVariableDeclStmt`. + * Holds if `foreach` statement `fes` could be converted to a `.Select()` call. + * That is, the loop variable is accessed only in the first statement of the + * block, and the access is not a cast. The first statement needs to be a + * `LocalVariableDeclStmt`. */ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { s = firstStmt(fes) and @@ -97,10 +99,10 @@ predicate missedSelectOpportunity(ForeachStmt fes, LocalVariableDeclStmt s) { } /** - * Holds if `ForeachStmt` could be converted to a `.Where()` call. That is, first - * statement of the loop is an `if`, which accesses the loop variable, and the body - * of the `if` is either a `continue` or there's nothing else in the loop than the - * `if`. + * Holds if `foreach` statement `fes` could be converted to a `.Where()` call. + * That is, first statement of the loop is an `if`, which accesses the loop + * variable, and the body of the `if` is either a `continue` or there's nothing + * else in the loop than the `if`. */ predicate missedWhereOpportunity(ForeachStmt fes, IfStmt is) { // The very first thing the foreach loop does is test its iteration variable. diff --git a/csharp/ql/src/external/CodeDuplication.qll b/csharp/ql/src/external/CodeDuplication.qll index 25dac79bd8c..f4165e599e8 100644 --- a/csharp/ql/src/external/CodeDuplication.qll +++ b/csharp/ql/src/external/CodeDuplication.qll @@ -276,7 +276,7 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) { ) } -/** Holds if the two files are similar or duplated. */ +/** Holds if the two files are similar or duplicated. */ predicate fileLevelDuplication(File f, File other) { similarFiles(f, other, _) or duplicateFiles(f, other, _) } diff --git a/csharp/ql/src/semmle/code/cil/Access.qll b/csharp/ql/src/semmle/code/cil/Access.qll index 871e6f7b416..e42a883a2e5 100644 --- a/csharp/ql/src/semmle/code/cil/Access.qll +++ b/csharp/ql/src/semmle/code/cil/Access.qll @@ -31,7 +31,7 @@ class ReadRefAccess extends ReadAccess, ReadRef { } /** An instruction that writes a variable. */ class WriteAccess extends VariableAccess, @cil_write_access { - /** Gets the `Expr` whose value is used in this variable write. */ + /** Gets the expression whose value is used in this variable write. */ Expr getExpr() { none() } } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index c833f6fa868..3aad183b401 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -1011,7 +1011,7 @@ class RangeExpr extends Expr, @range_expr { /** An index expression, for example `^1` meaning "1 from the end". */ class IndexExpr extends Expr, @index_expr { - /** Gets the sub expression of this `IndexExpr`. */ + /** Gets the sub expression of this index expression. */ Expr getExpr() { result.getParent() = this } override string toString() { result = "^..." } diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll index 4c7c7c03e69..517499ef76c 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/EntityFramework.qll @@ -8,7 +8,10 @@ private import semmle.code.csharp.frameworks.system.collections.Generic private import semmle.code.csharp.frameworks.Sql private import semmle.code.csharp.dataflow.LibraryTypeDataFlow -/** Definitions relating to the `System.ComponentModel.DataAnnotations`. */ +/** + * Definitions relating to the `System.ComponentModel.DataAnnotations` + * namespace. + */ module DataAnnotations { /** Class for `NotMappedAttribute`. */ class NotMappedAttribute extends Attribute { @@ -22,7 +25,7 @@ module DataAnnotations { /** * Definitions relating to the `Microsoft.EntityFrameworkCore` or - * `System.Data.Entity`. + * `System.Data.Entity` namespaces. */ module EntityFramework { /** An EF6 or EFCore namespace. */ diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll index 5f92060eaad..a6602899eaf 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/Linq.qll @@ -5,7 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.System as System -/** Definitions relating to the `System.Linq`. */ +/** Definitions relating to the `System.Linq` namespace. */ module SystemLinq { /** The `System.Linq` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll index 3ce97160ddf..a4aaa25611d 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Common.qll @@ -5,7 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Data as Data -/** Definitions relating to the `System.Data.Common`. */ +/** Definitions relating to the `System.Data.Common` namespace. */ module SystemDataCommon { /** The `System.Data.Common` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll index f172e96ea7d..2aaa9a5889a 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/data/Entity.qll @@ -5,7 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Data as Data -/** Definitions relating to the `System.Data.Entity`. */ +/** Definitions relating to the `System.Data.Entity` namespace. */ module SystemDataEntity { /** The `System.Data.Entity` namespace. */ class Namespace extends csharp::Namespace { @@ -79,7 +79,7 @@ module SystemDataEntity { } } -/** Definitions relating to the `System.Data.Entity.Infrastructure`. */ +/** Definitions relating to the `System.Data.Entity.Infrastructure` namespace. */ module SystemDataEntityInfrastructure { /** The `System.Data.Entity.Infrastructure` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll index 5cbc279bf4a..c4126834d20 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/linq/Expressions.qll @@ -5,7 +5,7 @@ private import csharp as csharp private import semmle.code.csharp.frameworks.system.Linq -/** Definitions relating to the `System.Linq.Expressions`. */ +/** Definitions relating to the `System.Linq.Expressions` namespace. */ module SystemLinqExpressions { /** The `System.Linq.Expressions` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll b/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll index d202350d035..9374d7c282f 100644 --- a/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll +++ b/csharp/ql/src/semmle/code/csharp/frameworks/system/xml/XPath.qll @@ -3,7 +3,7 @@ import csharp as csharp private import semmle.code.csharp.frameworks.system.Xml as xml -/** Definitions relating to the `System.Xml.XPath`. */ +/** Definitions relating to the `System.Xml.XPath` namespace. */ module SystemXmlXPath { /** The `System.Xml.XPath` namespace. */ class Namespace extends csharp::Namespace { diff --git a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll index 4c9970e2adb..b5330ce770e 100644 --- a/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll +++ b/csharp/ql/src/semmle/code/csharp/metrics/Coupling.qll @@ -223,8 +223,8 @@ predicate shareFieldOrProperty(ValueOrRefType t, Method m1, Method m2) { } /** - * Holds if `Method` `m` is declared in `ValueOrRefType` `t`, and if there's a - * `FieldAccess` or `PropertyAccess` in `m` that accesses `Declaration` `d`. + * Holds if the declaring type of method `m` is `t` and `m` accesses declaration + * `d`, which is either a field or a property. */ predicate methodUsesFieldOrProperty(ValueOrRefType t, Method m, Declaration d) { m.getDeclaringType() = t and diff --git a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll index 14a7a48361c..ece42b188c0 100644 --- a/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll +++ b/csharp/ql/src/semmle/code/csharp/serialization/Deserializers.qll @@ -8,9 +8,7 @@ import csharp /** An unsafe deserializer. */ abstract class UnsafeDeserializer extends Callable { } -/** - * Known unsafe deserializer methods in the `System.*` namespace. - */ +/** An unsafe deserializer method in the `System.*` namespace. */ class SystemDeserializer extends UnsafeDeserializer { SystemDeserializer() { this @@ -51,9 +49,7 @@ class SystemDeserializer extends UnsafeDeserializer { } } -/** - * Known unsafe deserializer methods in the `Microsoft.*` namespace. - */ +/** An unsafe deserializer method in the `Microsoft.*` namespace. */ class MicrosoftDeserializer extends UnsafeDeserializer { MicrosoftDeserializer() { this.hasQualifiedName("Microsoft.Web.Design.Remote.ProxyObject", "DecodeValue") @@ -61,8 +57,8 @@ class MicrosoftDeserializer extends UnsafeDeserializer { } /** - * Unsafe deserializer methods that call unsafe deserializers on the - * parameters. + * An unsafe deserializer method that calls any unsafe deserializer on any of + * the parameters. */ class WrapperDeserializer extends UnsafeDeserializer { WrapperDeserializer() { From deff36e9af3eeb1c0bd5dfef68509e2c5c8ee0de Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 28 Aug 2020 08:52:40 +0200 Subject: [PATCH 136/146] Python: fstring taint change note should be for 1.26 This fixes problem introduced in https://github.com/github/codeql/pull/4127 --- change-notes/1.25/analysis-python.md | 1 - change-notes/1.26/analysis-python.md | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 change-notes/1.26/analysis-python.md diff --git a/change-notes/1.25/analysis-python.md b/change-notes/1.25/analysis-python.md index 7a9c437a093..5d0fc69ec80 100644 --- a/change-notes/1.25/analysis-python.md +++ b/change-notes/1.25/analysis-python.md @@ -20,4 +20,3 @@ The following changes in version 1.25 affect Python analysis in all applications ## Changes to libraries * Importing `semmle.python.web.HttpRequest` will no longer import `UntrustedStringKind` transitively. `UntrustedStringKind` is the most commonly used non-abstract subclass of `ExternalStringKind`. If not imported (by one mean or another), taint-tracking queries that concern `ExternalStringKind` will not produce any results. Please ensure such queries contain an explicit import (`import semmle.python.security.strings.Untrusted`). -* Added support for tainted f-strings. diff --git a/change-notes/1.26/analysis-python.md b/change-notes/1.26/analysis-python.md new file mode 100644 index 00000000000..f60eb6b4354 --- /dev/null +++ b/change-notes/1.26/analysis-python.md @@ -0,0 +1,22 @@ +# Improvements to Python analysis + +The following changes in version 1.26 affect Python analysis in all applications. + +## General improvements + + +## New queries + +| **Query** | **Tags** | **Purpose** | +|-----------------------------|-----------|--------------------------------------------------------------------| + + +## Changes to existing queries + +| **Query** | **Expected impact** | **Change** | +|----------------------------|------------------------|------------------------------------------------------------------| + + +## Changes to libraries + +* Added taint tracking support for string formatting through f-strings. From 496d856c48215ec03e73c23eb77c30812736607a Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 28 Aug 2020 10:49:33 +0200 Subject: [PATCH 137/146] Python: Reformualte explanation of experience from JS --- .../experimental/dataflow/internal/TaintTrackingPrivate.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll index 0f71d2aa92e..3e32cb8036e 100644 --- a/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/TaintTrackingPrivate.qll @@ -36,8 +36,8 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT * Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to concatenation. * * Note that since we cannot easily distinguish interesting types (like string, list, tuple), - * we consider any `+` operation to propagate taint. After consulting with the JS team, this - * doesn't sound like it is a big problem in practice. + * we consider any `+` operation to propagate taint. This is what is done in the JS libraries, + * and isn't a big problem in practice. */ predicate concatStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) { exists(BinaryExprNode add | add = nodeTo.getNode() | From f4060723bbde76150dae54eb10647ec95f869404 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 28 Aug 2020 12:21:37 +0200 Subject: [PATCH 138/146] add stats for new properties --- .../ql/src/semmlecode.javascript.dbscheme.stats | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index 7e352454e59..b32bd3d513d 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -422,6 +422,18 @@ 222 +@assignlogandexpr +1 + + +@assignlogorexpr +1 + + +@assignnullishcoalescingexpr +1 + + @preincexpr 1792 From 9503c5d8bb9320a4c53824db4cf7450f56c7a4f3 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 28 Aug 2020 12:59:11 +0200 Subject: [PATCH 139/146] Python: Add post-update nodes --- .../internal/DataFlowImplConsistency.qll | 18 +++--- .../internal/DataFlowImplConsistency.qll | 18 +++--- .../internal/DataFlowImplConsistency.qll | 18 +++--- .../internal/DataFlowImplConsistency.qll | 18 +++--- .../internal/DataFlowImplConsistency.qll | 18 +++--- .../dataflow/internal/DataFlowPrivate.qll | 55 +++++++++++++++++-- .../dataflow/internal/DataFlowPublic.qll | 4 +- .../dataflow/basic/local.expected | 1 + .../dataflow/basic/sinks.expected | 1 + .../dataflow/basic/sources.expected | 1 + .../consistency/dataflow-consistency.expected | 17 ------ .../experimental/dataflow/coverage/classes.py | 8 +-- 12 files changed, 115 insertions(+), 62 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll index 5bacc138501..920855517c9 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplConsistency.qll @@ -123,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -152,12 +162,6 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll index 5bacc138501..920855517c9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplConsistency.qll @@ -123,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -152,12 +162,6 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll index 5bacc138501..920855517c9 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplConsistency.qll @@ -123,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -152,12 +162,6 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll index 5bacc138501..920855517c9 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll @@ -123,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -152,12 +162,6 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll b/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll index 5bacc138501..920855517c9 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowImplConsistency.qll @@ -123,8 +123,18 @@ module Consistency { n.getEnclosingCallable() != call.getEnclosingCallable() } + // This predicate helps the compiler forget that in some languages + // it is impossible for a result of `getPreUpdateNode` to be an + // instance of `PostUpdateNode`. + private Node getPre(PostUpdateNode n) { + result = n.getPreUpdateNode() + or + none() + } + query predicate postIsNotPre(PostUpdateNode n, string msg) { - n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node." + getPre(n) = n and + msg = "PostUpdateNode should not equal its pre-update node." } query predicate postHasUniquePre(PostUpdateNode n, string msg) { @@ -152,12 +162,6 @@ module Consistency { msg = "Origin of readStep is missing a PostUpdateNode." } - query predicate storeIsPostUpdate(Node n, string msg) { - storeStep(_, _, n) and - not n instanceof PostUpdateNode and - msg = "Store targets should be PostUpdateNodes." - } - query predicate argHasPostUpdate(ArgumentNode n, string msg) { not hasPost(n) and not isImmutableOrUnobservable(n) and diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll index c022bd86575..3a4dab619f2 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll @@ -15,6 +15,32 @@ class DataFlowCfgNode extends ControlFlowNode { DataFlowCfgNode() { isExpressionNode(this) } } +/** A data flow node which should have an associated post-update node. */ +abstract class PreUpdateNode extends Node { } + +/** An argument might have its value changed as a result of a call. */ +class ArgumentPreUpdateNode extends PreUpdateNode, ArgumentNode { } + +/** An object might have its value changed after a store. */ +class StorePreUpdateNode extends PreUpdateNode, CfgNode { + StorePreUpdateNode() { + exists(Attribute a | + node = a.getObject().getAFlowNode() and + a.getCtx() instanceof Store + ) + } +} + +/** A node marking the state change of an object after a read */ +class ReadPreUpdateNode extends PreUpdateNode, CfgNode { + ReadPreUpdateNode() { + exists(Attribute a | + node = a.getObject().getAFlowNode() and + a.getCtx() instanceof Load + ) + } +} + /** * A node associated with an object after an operation that might have * changed its state. @@ -24,12 +50,21 @@ class DataFlowCfgNode extends ControlFlowNode { * an update to the field. * * Nodes corresponding to AST elements, for example `ExprNode`, usually refer - * to the value before the update with the exception of `ObjectCreation`, - * which represents the value after the constructor has run. + * to the value before the update. */ -abstract class PostUpdateNode extends Node { +class PostUpdateNode extends Node, TPostUpdateNode { + PreUpdateNode pre; + + PostUpdateNode() { this = TPostUpdateNode(pre) } + /** Gets the node before the state update. */ - abstract Node getPreUpdateNode(); + Node getPreUpdateNode() { result = pre } + + override string toString() { result = "[post] " + pre.toString() } + + override Scope getScope() { result = pre.getScope() } + + override Location getLocation() { result = pre.getLocation() } } class DataFlowExpr = Expr; @@ -98,7 +133,17 @@ module EssaFlow { predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) { not nodeFrom.(EssaNode).getVar() instanceof GlobalSsaVariable and not nodeTo.(EssaNode).getVar() instanceof GlobalSsaVariable and - EssaFlow::essaFlowStep(nodeFrom, nodeTo) + EssaFlow::essaFlowStep(update(nodeFrom), nodeTo) +} + +private Node update(Node node) { + exists(PostUpdateNode pun | + node = pun.getPreUpdateNode() and + result = pun + ) + or + not exists(PostUpdateNode pun | node = pun.getPreUpdateNode()) and + result = node } // TODO: Make modules for these headings diff --git a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll index e01604cbb61..81d7182a5ad 100644 --- a/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll +++ b/python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll @@ -20,7 +20,9 @@ newtype TNode = /** A node corresponding to an SSA variable. */ TEssaNode(EssaVariable var) or /** A node corresponding to a control flow node. */ - TCfgNode(DataFlowCfgNode node) + TCfgNode(DataFlowCfgNode node) or + /** A node representing the value of an object after a state change */ + TPostUpdateNode(PreUpdateNode pre) /** * An element, viewed as a node in a data flow graph. Either an SSA variable diff --git a/python/ql/test/experimental/dataflow/basic/local.expected b/python/ql/test/experimental/dataflow/basic/local.expected index 4777c30adfd..4bb6b8d6f5c 100644 --- a/python/ql/test/experimental/dataflow/basic/local.expected +++ b/python/ql/test/experimental/dataflow/basic/local.expected @@ -38,3 +38,4 @@ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a | | test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:7:19:7:19 | [post] ControlFlowNode for a | test.py:7:19:7:19 | [post] ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/sinks.expected b/python/ql/test/experimental/dataflow/basic/sinks.expected index 8b292d55b5e..5b58a0f844f 100644 --- a/python/ql/test/experimental/dataflow/basic/sinks.expected +++ b/python/ql/test/experimental/dataflow/basic/sinks.expected @@ -23,3 +23,4 @@ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:7:19:7:19 | [post] ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/basic/sources.expected b/python/ql/test/experimental/dataflow/basic/sources.expected index 8b292d55b5e..5b58a0f844f 100644 --- a/python/ql/test/experimental/dataflow/basic/sources.expected +++ b/python/ql/test/experimental/dataflow/basic/sources.expected @@ -23,3 +23,4 @@ | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | | test.py:7:5:7:20 | GSSA Variable a | | test.py:7:19:7:19 | ControlFlowNode for a | +| test.py:7:19:7:19 | [post] ControlFlowNode for a | diff --git a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected index 1d9e912351a..135ebd18779 100644 --- a/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected +++ b/python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected @@ -85,21 +85,4 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate -| test.py:152:9:152:16 | ControlFlowNode for List | Store targets should be PostUpdateNodes. | -| test.py:153:9:153:24 | ControlFlowNode for Dict | Store targets should be PostUpdateNodes. | argHasPostUpdate -| test.py:25:10:25:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:29:10:29:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:48:19:48:21 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. | -| test.py:51:10:51:12 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. | -| test.py:55:14:55:16 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. | -| test.py:59:11:59:11 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:67:11:67:14 | ControlFlowNode for cond | ArgumentNode is missing PostUpdateNode. | -| test.py:67:17:67:17 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:74:11:74:14 | ControlFlowNode for cond | ArgumentNode is missing PostUpdateNode. | -| test.py:74:17:74:17 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:81:13:81:13 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:86:13:86:13 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. | -| test.py:158:15:158:15 | ControlFlowNode for l | ArgumentNode is missing PostUpdateNode. | -| test.py:159:15:159:15 | ControlFlowNode for d | ArgumentNode is missing PostUpdateNode. | diff --git a/python/ql/test/experimental/dataflow/coverage/classes.py b/python/ql/test/experimental/dataflow/coverage/classes.py index 5039a65181d..7802c502a9e 100644 --- a/python/ql/test/experimental/dataflow/coverage/classes.py +++ b/python/ql/test/experimental/dataflow/coverage/classes.py @@ -93,7 +93,7 @@ class With_str: def __str__(self): SINK1(self) # Flow not found - OK() # Call not found # Call not found + OK() # Call not found return "Awesome" @@ -108,7 +108,7 @@ class With_bytes: def __bytes__(self): SINK1(self) # Flow not found - OK() # Call not found # Call not found + OK() # Call not found return b"Awesome" @@ -124,7 +124,7 @@ class With_format: def __format__(self, format_spec): SINK2(format_spec) # Flow not found SINK1(self) # Flow not found - OK() # Call not found # Call not found + OK() # Call not found return "Awesome" @@ -151,7 +151,7 @@ class With_lt: def __lt__(self, other): SINK2(other) # Flow not found SINK1(self) # Flow not found - OK() # Call not found # Call not found + OK() # Call not found return "" From 750735c70c3f0f362b3def4506cbbc47cbcf7d70 Mon Sep 17 00:00:00 2001 From: Rasmus Lerchedahl Petersen Date: Fri, 28 Aug 2020 15:00:01 +0200 Subject: [PATCH 140/146] Dataflow: Update test expectations --- .../dataflow/dataflow-tests/dataflow-consistency.expected | 1 - .../dataflow/dataflow-tests/dataflow-ir-consistency.expected | 1 - .../library-tests/dataflow/fields/dataflow-consistency.expected | 1 - .../dataflow/fields/dataflow-ir-consistency.expected | 1 - .../test/library-tests/syntax-zoo/dataflow-consistency.expected | 1 - .../library-tests/syntax-zoo/dataflow-ir-consistency.expected | 1 - 6 files changed, 6 deletions(-) diff --git a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected index 2f6b103bc0d..2972c41e900 100644 --- a/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected @@ -14,7 +14,6 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate | lambdas.cpp:18:7:18:7 | a | ArgumentNode is missing PostUpdateNode. | | lambdas.cpp:25:2:25:2 | b | ArgumentNode is missing PostUpdateNode. | 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 9b6b19b4957..9c819ceceed 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 @@ -29,5 +29,4 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate 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 70d78dfbc89..a804166e960 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/dataflow-consistency.expected @@ -16,7 +16,6 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate | A.cpp:41:15:41:21 | new | ArgumentNode is missing PostUpdateNode. | | A.cpp:55:12:55:19 | new | ArgumentNode is missing PostUpdateNode. | 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 81d239b8d7c..99d6808a0a2 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 @@ -23,5 +23,4 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate diff --git a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected index 3f9dcb1adf6..767ab6df54f 100644 --- a/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected +++ b/cpp/ql/test/library-tests/syntax-zoo/dataflow-consistency.expected @@ -60,7 +60,6 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate | builtin.cpp:15:31:15:35 | * ... | ArgumentNode is missing PostUpdateNode. | | conditional_destructors.cpp:30:9:30:13 | call to C1 | ArgumentNode is missing PostUpdateNode. | 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 434d7c30127..ee50bd638f9 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 @@ -1473,5 +1473,4 @@ postHasUniquePre uniquePostUpdate postIsInSameCallable reverseRead -storeIsPostUpdate argHasPostUpdate From ddb33c914bc84f6d8539179ee63df0b87a17b2f8 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 28 Aug 2020 15:13:18 +0200 Subject: [PATCH 141/146] C#: Add test that demonstrates issue with guards logic for `foreach` statements --- .../controlflow/guards/AbstractValue.expected | 52 +++++++++++-------- .../controlflow/guards/Collections.cs | 21 ++++++-- .../guards/GuardedControlFlowNode.expected | 2 + .../controlflow/guards/GuardedExpr.expected | 2 + .../controlflow/guards/Implications.expected | 28 +++++----- 5 files changed, 64 insertions(+), 41 deletions(-) diff --git a/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected b/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected index 25bc436216b..092643191f8 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/AbstractValue.expected @@ -18,7 +18,7 @@ abstractValue | 0 | Collections.cs:78:36:78:36 | 0 | | 0 | Collections.cs:80:35:80:35 | 0 | | 0 | Collections.cs:81:36:81:36 | 0 | -| 0 | Collections.cs:87:17:87:31 | 0 | +| 0 | Collections.cs:87:17:87:32 | 0 | | 0 | Guards.cs:12:24:12:24 | 0 | | 0 | Guards.cs:78:26:78:26 | 0 | | 0 | Guards.cs:80:25:80:25 | 0 | @@ -59,8 +59,8 @@ abstractValue | 1 | Guards.cs:331:17:331:19 | access to constant B | | 1 | Guards.cs:334:13:334:15 | access to constant B | | 1 | Guards.cs:335:18:335:18 | 1 | -| 3 | Collections.cs:55:13:55:41 | 3 | -| 3 | Collections.cs:63:17:63:45 | 3 | +| 3 | Collections.cs:55:13:55:42 | 3 | +| 3 | Collections.cs:63:17:63:46 | 3 | | 10 | Guards.cs:84:25:84:26 | 10 | | 10 | Guards.cs:86:26:86:27 | 10 | | empty | Collections.cs:54:13:54:16 | access to parameter args | @@ -69,22 +69,22 @@ abstractValue | empty | Collections.cs:58:9:58:13 | ... = ... | | empty | Collections.cs:58:13:58:13 | access to local variable x | | empty | Collections.cs:65:13:65:13 | access to local variable x | -| empty | Collections.cs:87:17:87:31 | array creation of type String[] | -| empty | Collections.cs:87:30:87:31 | { ..., ... } | -| empty | Collections.cs:88:22:88:23 | { ..., ... } | +| empty | Collections.cs:87:17:87:32 | array creation of type String[] | +| empty | Collections.cs:87:30:87:32 | { ..., ... } | +| empty | Collections.cs:88:22:88:24 | { ..., ... } | | false | Guards.cs:178:16:178:20 | false | | false | Guards.cs:181:53:181:57 | false | | false | Guards.cs:217:18:217:22 | false | | false | Guards.cs:228:18:228:22 | false | | false | Guards.cs:295:18:295:22 | false | | false | Guards.cs:305:18:305:22 | false | -| non-empty | Collections.cs:55:9:55:41 | ... = ... | -| non-empty | Collections.cs:55:13:55:41 | array creation of type String[] | -| non-empty | Collections.cs:55:25:55:41 | { ..., ... } | +| non-empty | Collections.cs:55:9:55:42 | ... = ... | +| non-empty | Collections.cs:55:13:55:42 | array creation of type String[] | +| non-empty | Collections.cs:55:26:55:42 | { ..., ... } | | non-empty | Collections.cs:56:9:56:13 | ... = ... | | non-empty | Collections.cs:56:13:56:13 | access to local variable x | -| non-empty | Collections.cs:63:17:63:45 | array creation of type String[] | -| non-empty | Collections.cs:63:29:63:45 | { ..., ... } | +| non-empty | Collections.cs:63:17:63:46 | array creation of type String[] | +| non-empty | Collections.cs:63:30:63:46 | { ..., ... } | | non-empty | Collections.cs:68:13:68:13 | access to local variable x | | non-empty | Collections.cs:89:9:89:32 | ... = ... | | non-empty | Collections.cs:89:13:89:32 | array creation of type String[] | @@ -155,11 +155,11 @@ abstractValue | non-null | Collections.cs:54:13:54:16 | access to parameter args | | non-null | Collections.cs:54:13:54:26 | call to method ToArray | | non-null | Collections.cs:55:9:55:9 | access to local variable x | -| non-null | Collections.cs:55:9:55:41 | ... = ... | -| non-null | Collections.cs:55:13:55:41 | array creation of type String[] | -| non-null | Collections.cs:55:27:55:29 | "a" | -| non-null | Collections.cs:55:32:55:34 | "b" | -| non-null | Collections.cs:55:37:55:39 | "c" | +| non-null | Collections.cs:55:9:55:42 | ... = ... | +| non-null | Collections.cs:55:13:55:42 | array creation of type String[] | +| non-null | Collections.cs:55:28:55:30 | "a" | +| non-null | Collections.cs:55:33:55:35 | "b" | +| non-null | Collections.cs:55:38:55:40 | "c" | | non-null | Collections.cs:56:9:56:9 | access to local variable x | | non-null | Collections.cs:56:9:56:13 | ... = ... | | non-null | Collections.cs:56:13:56:13 | access to local variable x | @@ -169,11 +169,11 @@ abstractValue | non-null | Collections.cs:58:9:58:9 | access to local variable x | | non-null | Collections.cs:58:9:58:13 | ... = ... | | non-null | Collections.cs:58:13:58:13 | access to local variable x | -| non-null | Collections.cs:63:17:63:45 | array creation of type String[] | -| non-null | Collections.cs:63:17:63:54 | call to method ToList | -| non-null | Collections.cs:63:31:63:33 | "a" | -| non-null | Collections.cs:63:36:63:38 | "b" | -| non-null | Collections.cs:63:41:63:43 | "c" | +| non-null | Collections.cs:63:17:63:46 | array creation of type String[] | +| non-null | Collections.cs:63:17:63:55 | call to method ToList | +| non-null | Collections.cs:63:32:63:34 | "a" | +| non-null | Collections.cs:63:37:63:39 | "b" | +| non-null | Collections.cs:63:42:63:44 | "c" | | non-null | Collections.cs:64:9:64:9 | access to local variable x | | non-null | Collections.cs:65:13:65:13 | access to local variable x | | non-null | Collections.cs:67:13:67:13 | access to local variable x | @@ -214,14 +214,20 @@ abstractValue | non-null | Collections.cs:82:24:82:30 | access to local function IsEmpty | | non-null | Collections.cs:82:24:82:30 | delegate creation of type Func | | non-null | Collections.cs:82:24:82:30 | this access | -| non-null | Collections.cs:87:17:87:31 | array creation of type String[] | -| non-null | Collections.cs:88:22:88:23 | array creation of type String[] | +| non-null | Collections.cs:87:17:87:32 | array creation of type String[] | +| non-null | Collections.cs:88:22:88:24 | array creation of type String[] | | non-null | Collections.cs:89:9:89:9 | access to local variable x | | non-null | Collections.cs:89:9:89:32 | ... = ... | | non-null | Collections.cs:89:13:89:32 | array creation of type String[] | | non-null | Collections.cs:89:28:89:30 | "a" | | non-null | Collections.cs:90:22:90:28 | array creation of type String[] | | non-null | Collections.cs:90:24:90:26 | "a" | +| non-null | Collections.cs:95:29:95:32 | access to parameter args | +| non-null | Collections.cs:96:13:96:19 | access to type Console | +| non-null | Collections.cs:96:31:96:34 | access to parameter args | +| non-null | Collections.cs:101:29:101:32 | access to parameter args | +| non-null | Collections.cs:103:9:103:15 | access to type Console | +| non-null | Collections.cs:103:27:103:30 | access to parameter args | | non-null | Guards.cs:12:13:12:13 | access to parameter s | | non-null | Guards.cs:14:13:14:19 | access to type Console | | non-null | Guards.cs:14:31:14:31 | access to parameter s | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs index 65f07491ae5..4c4980c4635 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs @@ -52,7 +52,7 @@ public class Collections var x = args.ToArray(); args.Clear(); x = args.ToArray(); - x = new string[]{ "a", "b", "c" }; + x = new string[] { "a", "b", "c" }; x = x; x = new string[0]; x = x; @@ -60,7 +60,7 @@ public class Collections void M6() { - var x = new string[]{ "a", "b", "c" }.ToList(); + var x = new string[] { "a", "b", "c" }.ToList(); x.Clear(); if (x.Count == 0) { @@ -84,10 +84,23 @@ public class Collections void M8() { - var x = new string[] {}; - string[] y = {}; + var x = new string[] { }; + string[] y = { }; x = new string[] { "a" }; string[] z = { "a" }; } + + void M9(string[] args) + { + foreach (var arg in args) + Console.WriteLine(args); // guarded by `args` being non-empty + } + + void M10(string[] args) + { + foreach (var arg in args) + ; + Console.WriteLine(args); // INCORRECT: guarded by `args` being empty + } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected index 7a4cbaf0df4..2290483dc18 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected @@ -37,6 +37,8 @@ | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty | | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | +| Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty | +| Collections.cs:103:27:103:30 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | empty | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index e8d85631cb7..110efa2fcab 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -37,6 +37,8 @@ | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | Collections.cs:65:13:65:13 | access to local variable x | empty | | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | +| Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty | +| Collections.cs:103:27:103:30 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | empty | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected index 69bfefd6d9f..59f89c30800 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Implications.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/Implications.expected @@ -180,26 +180,26 @@ | Collections.cs:45:17:45:26 | call to method Any | true | Collections.cs:45:17:45:20 | access to parameter args | non-empty | | Collections.cs:50:13:50:27 | ... == ... | false | Collections.cs:50:13:50:16 | access to parameter args | non-empty | | Collections.cs:50:13:50:27 | ... == ... | true | Collections.cs:50:13:50:16 | access to parameter args | empty | -| Collections.cs:56:13:56:13 | access to local variable x | empty | Collections.cs:55:13:55:41 | array creation of type String[] | empty | -| Collections.cs:56:13:56:13 | access to local variable x | non-empty | Collections.cs:55:13:55:41 | array creation of type String[] | non-empty | -| Collections.cs:56:13:56:13 | access to local variable x | non-null | Collections.cs:55:13:55:41 | array creation of type String[] | non-null | -| Collections.cs:56:13:56:13 | access to local variable x | null | Collections.cs:55:13:55:41 | array creation of type String[] | null | +| Collections.cs:56:13:56:13 | access to local variable x | empty | Collections.cs:55:13:55:42 | array creation of type String[] | empty | +| Collections.cs:56:13:56:13 | access to local variable x | non-empty | Collections.cs:55:13:55:42 | array creation of type String[] | non-empty | +| Collections.cs:56:13:56:13 | access to local variable x | non-null | Collections.cs:55:13:55:42 | array creation of type String[] | non-null | +| Collections.cs:56:13:56:13 | access to local variable x | null | Collections.cs:55:13:55:42 | array creation of type String[] | null | | Collections.cs:58:13:58:13 | access to local variable x | empty | Collections.cs:57:13:57:25 | array creation of type String[] | empty | | Collections.cs:58:13:58:13 | access to local variable x | non-empty | Collections.cs:57:13:57:25 | array creation of type String[] | non-empty | | Collections.cs:58:13:58:13 | access to local variable x | non-null | Collections.cs:57:13:57:25 | array creation of type String[] | non-null | | Collections.cs:58:13:58:13 | access to local variable x | null | Collections.cs:57:13:57:25 | array creation of type String[] | null | -| Collections.cs:64:9:64:9 | access to local variable x | empty | Collections.cs:63:17:63:54 | call to method ToList | empty | -| Collections.cs:64:9:64:9 | access to local variable x | non-empty | Collections.cs:63:17:63:54 | call to method ToList | non-empty | -| Collections.cs:64:9:64:9 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:64:9:64:9 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | -| Collections.cs:65:13:65:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:65:13:65:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | +| Collections.cs:64:9:64:9 | access to local variable x | empty | Collections.cs:63:17:63:55 | call to method ToList | empty | +| Collections.cs:64:9:64:9 | access to local variable x | non-empty | Collections.cs:63:17:63:55 | call to method ToList | non-empty | +| Collections.cs:64:9:64:9 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:64:9:64:9 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | +| Collections.cs:65:13:65:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:65:13:65:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | | Collections.cs:65:13:65:24 | ... == ... | false | Collections.cs:65:13:65:13 | access to local variable x | non-empty | | Collections.cs:65:13:65:24 | ... == ... | true | Collections.cs:65:13:65:13 | access to local variable x | empty | -| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | -| Collections.cs:68:13:68:13 | access to local variable x | non-null | Collections.cs:63:17:63:54 | call to method ToList | non-null | -| Collections.cs:68:13:68:13 | access to local variable x | null | Collections.cs:63:17:63:54 | call to method ToList | null | +| Collections.cs:67:13:67:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:67:13:67:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | +| Collections.cs:68:13:68:13 | access to local variable x | non-null | Collections.cs:63:17:63:55 | call to method ToList | non-null | +| Collections.cs:68:13:68:13 | access to local variable x | null | Collections.cs:63:17:63:55 | call to method ToList | null | | Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:35:74:35 | access to parameter s | non-null | | Collections.cs:74:35:74:41 | ... == ... | true | Collections.cs:74:40:74:41 | "" | non-null | | Collections.cs:75:17:75:33 | call to method Any | true | Collections.cs:75:17:75:20 | access to parameter args | non-empty | From b205702853e17f110ad0b0b7174e1b432391093d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 28 Aug 2020 15:18:09 +0200 Subject: [PATCH 142/146] C#: Fix bug in guards logic for `foreach` loops --- csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll | 7 ++++++- .../test/library-tests/controlflow/guards/Collections.cs | 2 +- .../controlflow/guards/GuardedControlFlowNode.expected | 1 - .../library-tests/controlflow/guards/GuardedExpr.expected | 1 - 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index f990a06c0e4..89042f7de07 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -212,7 +212,12 @@ module AbstractValues { c.isValidFor(cfe) and foreachEmptiness(fs, cfe) and e = fs.getIterableExpr() - ) + ) and + // Only when taking the non-empty successor do we know that the original iterator + // expression was non-empty. When taking the empty successor, we may have already + // iterated through the `foreach` loop zero or more times, hence the iterator + // expression can be both empty and non-empty + this.isNonEmpty() } override EmptyCollectionValue getDualValue() { diff --git a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs index 4c4980c4635..93a19595c84 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/Collections.cs +++ b/csharp/ql/test/library-tests/controlflow/guards/Collections.cs @@ -100,7 +100,7 @@ public class Collections { foreach (var arg in args) ; - Console.WriteLine(args); // INCORRECT: guarded by `args` being empty + Console.WriteLine(args); } } diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected index 2290483dc18..e8b4f96bb93 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected @@ -38,7 +38,6 @@ | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty | -| Collections.cs:103:27:103:30 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | empty | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected index 110efa2fcab..50159853ea7 100644 --- a/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedExpr.expected @@ -38,7 +38,6 @@ | Collections.cs:67:13:67:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:68:13:68:13 | access to local variable x | Collections.cs:65:13:65:24 | ... == ... | Collections.cs:65:13:65:13 | access to local variable x | true | | Collections.cs:96:31:96:34 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | Collections.cs:95:29:95:32 | access to parameter args | non-empty | -| Collections.cs:103:27:103:30 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | Collections.cs:101:29:101:32 | access to parameter args | empty | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | | Guards.cs:12:13:12:13 | access to parameter s | Guards.cs:10:16:10:24 | ... == ... | Guards.cs:10:16:10:16 | access to parameter s | false | | Guards.cs:14:31:14:31 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | Guards.cs:10:16:10:16 | access to parameter s | non-null | From 4f07733b06ea62aab3da3b455246089d08a1cd11 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Sun, 30 Aug 2020 04:54:02 +0530 Subject: [PATCH 143/146] remove U+200B --- .../security/CWE-079/semmle/tests/WebsocketXss.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java index 2fc9998b775..6d069c6f118 100644 --- a/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java +++ b/java/ql/test/query-tests/security/CWE-079/semmle/tests/WebsocketXss.java @@ -14,7 +14,7 @@ // HttpClient client = HttpClient.newBuilder().build(); // CompletableFuture ws = client.newWebSocketBuilder() // .buildAsync(URI.create("ws://websocket.example.com"), null); -// ws.get().sendText​(message, false); +// ws.get().sendText(message, false); // } catch (Exception e) { // // TODO: handle exception // } @@ -24,4 +24,4 @@ // }; // } -// } \ No newline at end of file +// } From 66d39bb5f69fc757d8870f5b1dcb3b1fb37be2b0 Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Mon, 31 Aug 2020 10:39:00 +0200 Subject: [PATCH 144/146] Java: remove InefficientToArray.ql This query was deprecated 4 years ago. Fixes: #4167 --- .../src/Performance/InefficientToArray.java | 28 --------- .../src/Performance/InefficientToArray.qhelp | 61 ------------------- java/ql/src/Performance/InefficientToArray.ql | 53 ---------------- 3 files changed, 142 deletions(-) delete mode 100644 java/ql/src/Performance/InefficientToArray.java delete mode 100644 java/ql/src/Performance/InefficientToArray.qhelp delete mode 100644 java/ql/src/Performance/InefficientToArray.ql diff --git a/java/ql/src/Performance/InefficientToArray.java b/java/ql/src/Performance/InefficientToArray.java deleted file mode 100644 index 7ad20d7e1cd..00000000000 --- a/java/ql/src/Performance/InefficientToArray.java +++ /dev/null @@ -1,28 +0,0 @@ -class Company { - private List customers = ...; - - public Customer[] getCustomerArray() { - // AVOID: Inefficient call to 'toArray' with zero-length argument - return customers.toArray(new Customer[0]); - } -} - -class Company { - private List customers = ...; - - public Customer[] getCustomerArray() { - // GOOD: More efficient call to 'toArray' with argument that is big enough to store the list - return customers.toArray(new Customer[customers.size()]); - } -} - -class Company { - private static final Customer[] NO_CUSTOMERS = new Customer[0]; - - private List customers = ...; - - public Customer[] getCustomerArray() { - // GOOD: Reuse same zero-length array on every invocation - return customers.toArray(NO_CUSTOMERS); - } -} \ No newline at end of file diff --git a/java/ql/src/Performance/InefficientToArray.qhelp b/java/ql/src/Performance/InefficientToArray.qhelp deleted file mode 100644 index 79bea193a5f..00000000000 --- a/java/ql/src/Performance/InefficientToArray.qhelp +++ /dev/null @@ -1,61 +0,0 @@ - - - - - -

    The java.util.Collection interface provides a toArray -method that can be used to convert a collection of objects into an array of a particular -type. This method takes an array as an argument, which is used for two purposes. -Firstly, it determines the type of the returned array. Secondly, if it is big enough to -hold all values in the collection, it is filled with those values and returned; -otherwise, a new array of sufficient size and the appropriate type is allocated and -filled.

    - -

    It is common to pass a fresh zero-length array to toArray, -simply because it is easy to construct one. Unfortunately, this allocation is wasteful, -because the array clearly is not big enough to hold the elements of the collection. This can cause -considerable garbage collector churn, impacting performance.

    - -
    - - -

    There are at least two ways to address this issue.

    - -

    The first is to always call toArray with a new array allocated with a -sufficient size to hold the contents of the collection. Usually, this involves calling -the collection's size method and allocating an array with that many -elements. While it may seem odd that adding a call to size improves performance, if you -do not pass a large enough array, the toArray method makes this call automatically. -Calling size explicitly and then calling toArray with a large enough array -avoids the possible creation of two arrays (one too small and consequently unused).

    - -

    The second approach is to add a static field holding a constant zero-length array to the -enclosing class, and pass that field to toArray. In this case, toArray -will end up allocating a new array in (almost) every case, but because the same zero-length array -is reused every time, there is almost no overhead. (Note that if toArray -is invoked on an empty collection, it will return the passed-in array. If your code expects -a new array from every invocation of toArray, you should use the first method.)

    - -
    - - -

    In the following example, the first version of class Company uses an inefficient -call to toArray by passing a zero-length array. The second and third version -illustrate the two ways of addressing this issue outlined above.

    - - - -
    - - - -
  • - Java Platform, Standard Edition 6, API Specification: - toArray. -
  • - - -
    -
    diff --git a/java/ql/src/Performance/InefficientToArray.ql b/java/ql/src/Performance/InefficientToArray.ql deleted file mode 100644 index 13684891a6c..00000000000 --- a/java/ql/src/Performance/InefficientToArray.ql +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @name Inefficient toArray on zero-length argument - * @description Calling 'Collection.toArray' with a zero-length array argument is inefficient. - * @kind problem - * @problem.severity recommendation - * @precision low - * @id java/inefficient-to-array - * @deprecated - */ - -import java - -/* - * This method uses the toArray() method of a collection derived class, and passes in a - * zero-length prototype array argument. - * - * It is more efficient to use myCollection.toArray(new Foo[myCollection.size()]). - * If the array passed in is big enough to store all of the elements of the collection, - * then it is populated and returned directly. This avoids the need to create a - * second array (by reflection) to return as the result. - * - * The new array has to be created as the argument value. Values in both branches of - * a conditional has to be an empty array. - */ - -predicate emptyArrayLiteral(Expr e) { - // ArrayCreationExpr with zero-length init expr - exists(ArrayCreationExpr arr | arr = e | - exists(arr.getInit()) and - not exists(arr.getInit().getAnInit()) - ) - or - // ArrayCreationExpr where 0th dimension is zero literal - e.(ArrayCreationExpr).getDimension(0).(IntegerLiteral).getIntValue() = 0 - or - exists(ConditionalExpr cond | cond = e | - emptyArrayLiteral(cond.getTrueExpr()) and - emptyArrayLiteral(cond.getFalseExpr()) - ) -} - -class EmptyArrayLiteral extends Expr { - EmptyArrayLiteral() { emptyArrayLiteral(this) } -} - -from EmptyArrayLiteral l, MethodAccess ma, Method m, GenericInterface coll -where - coll.hasQualifiedName("java.util", "Collection") and - ma.getMethod() = m and - m.hasName("toArray") and - m.getDeclaringType().getASupertype*().getSourceDeclaration() = coll and - ma.getArgument(0) = l -select ma, "Collection.toArray(...) called with zero-length array argument." From 22ccae6006e7dfa019a49ca4b79714659e95ba8e Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Mon, 31 Aug 2020 11:55:10 +0100 Subject: [PATCH 145/146] JavaScript: Make `PromiseFlow` module public. --- javascript/ql/src/semmle/javascript/Promises.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Promises.qll b/javascript/ql/src/semmle/javascript/Promises.qll index a893c185828..a8fb3dc1fc3 100644 --- a/javascript/ql/src/semmle/javascript/Promises.qll +++ b/javascript/ql/src/semmle/javascript/Promises.qll @@ -249,7 +249,7 @@ private class PromiseStep extends PreCallGraphStep { * This module defines how data-flow propagates into and out of a Promise. * The data-flow is based on pseudo-properties rather than tainting the Promise object (which is what `PromiseTaintStep` does). */ -private module PromiseFlow { +module PromiseFlow { private predicate valueProp = Promises::valueProp/0; private predicate errorProp = Promises::errorProp/0; From 2bdd3d7712182464ad17110dacdce1a0e9372af8 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Mon, 31 Aug 2020 17:28:51 +0200 Subject: [PATCH 146/146] Apply qldoc suggestions Co-authored-by: Anders Schack-Mulligen --- java/ql/src/semmle/code/java/security/XSS.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index df1a1606f12..2d2d14295f8 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -23,7 +23,7 @@ abstract class XssSanitizer extends DataFlow::Node { } abstract class XssAdditionalTaintStep extends TaintTracking2::Unit { /** * Holds if the step from `node1` to `node2` should be considered a taint - * step for all configurations. + * step for XSS taint configurations. */ abstract predicate step(DataFlow::Node node1, DataFlow::Node node2); } @@ -119,7 +119,7 @@ private class ServletWriterSourceToWritingMethodFlowConfig extends TaintTracking } } -/** A class representing methods that can be used to output data. */ +/** A method that can be used to output data to an output stream or writer. */ private class WritingMethod extends Method { WritingMethod() { getDeclaringType().getASupertype*().hasQualifiedName("java.io", _) and @@ -131,7 +131,7 @@ private class WritingMethod extends Method { } } -/** A class representing methods that provides access to an output stream or writer. */ +/** An output stream or writer that writes to a servlet response. */ class ServletWriterSource extends MethodAccess { ServletWriterSource() { this.getMethod() instanceof ServletResponseGetWriterMethod