diff --git a/change-notes/1.20/analysis-cpp.md b/change-notes/1.20/analysis-cpp.md index 16b18b07855..66778a04ebd 100644 --- a/change-notes/1.20/analysis-cpp.md +++ b/change-notes/1.20/analysis-cpp.md @@ -10,11 +10,13 @@ |-----------------------------|-----------|--------------------------------------------------------------------| | Use of string copy function in a condition (`cpp/string-copy-return-value-as-boolean`) | correctness | This query identifies calls to string copy functions used in conditions, where it's likely that a different function was intended to be called. | | Lossy function result cast (`cpp/lossy-function-result-cast`) | correctness | Finds function calls whose result type is a floating point type, which are implicitly cast to an integral type. Newly available but not displayed by default on LGTM. | +| Array argument size mismatch (`cpp/array-arg-size-mismatch`) | reliability | Finds function calls where the size of an array being passed is smaller than the array size of the declared parameter. Newly displayed on LGTM. | ## Changes to existing queries | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Array argument size mismatch (`cpp/array-arg-size-mismatch`) | Fewer false positives | An exception has been added to this query for variable sized arrays. | | Suspicious add with sizeof (`cpp/suspicious-add-sizeof`) | Fewer false positives | Pointer arithmetic on `char * const` expressions (and other variations of `char *`) are now correctly excluded from the results. | | Suspicious pointer scaling (`cpp/suspicious-pointer-scaling`) | Fewer false positives | False positives involving types that are not uniquely named in the snapshot have been fixed. | | Call to memory access function may overflow buffer (`cpp/overflow-buffer`) | More correct results | Calls to `fread` are now examined by this query. | diff --git a/change-notes/1.20/analysis-javascript.md b/change-notes/1.20/analysis-javascript.md index e71ed1a1902..1b1b2502db3 100644 --- a/change-notes/1.20/analysis-javascript.md +++ b/change-notes/1.20/analysis-javascript.md @@ -37,6 +37,7 @@ | Useless assignment to property. | Fewer false-positive results | This rule now treats assignments with complex right-hand sides correctly. | | Unsafe dynamic method access | Fewer false-positive results | This rule no longer flags concatenated strings as unsafe method names. | | Unvalidated dynamic method call | More true-positive results | This rule now flags concatenated strings as unvalidated method names in more cases. | +| Useless conditional | More true-positive results | This rule now flags additional uses of function call values. | ## Changes to QL libraries diff --git a/change-notes/1.20/analysis-python.md b/change-notes/1.20/analysis-python.md index e4ff53a37d8..cf945ba0dce 100644 --- a/change-notes/1.20/analysis-python.md +++ b/change-notes/1.20/analysis-python.md @@ -14,12 +14,14 @@ Removes false positives seen when using Python 3.6, but not when using earlier v | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| | Default version of SSL/TLS may be insecure (`py/insecure-default-protocol`) | security, external/cwe/cwe-327 | Finds instances where an insecure default protocol may be used. Results are shown on LGTM by default. | +| Overly permissive file permissions (`py/overly-permissive-file`) | security, external/cwe/cwe-732 | Finds instances where a file is created with overly permissive permissions. Results are not shown on LGTM by default. | | Use of insecure SSL/TLS version (`py/insecure-protocol`) | security, external/cwe/cwe-327 | Finds instances where a known insecure protocol has been specified. Results are shown on LGTM by default. | ## Changes to existing queries | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| +| Comparison using is when operands support \_\_eq\_\_ (`py/comparison-using-is`) | Fewer false positive results | Results where one of the objects being compared is an enum member are no longer reported. | | Mutation of descriptor in \_\_get\_\_ or \_\_set\_\_ method (`py/mutable-descriptor`) | Fewer false positive results | Results where the mutation does not occur when calling one of the `__get__`, `__set__` or `__delete__` methods are no longer reported. | | Unused import (`py/unused-import`) | Fewer false positive results | Results where the imported module is used in a `doctest` string are no longer reported. | | Unused import (`py/unused-import`) | Fewer false positive results | Results where the imported module is used in a type-hint comment are no longer reported. | diff --git a/cpp/config/suites/c/correctness b/cpp/config/suites/c/correctness index e53ccda1187..442e618854d 100644 --- a/cpp/config/suites/c/correctness +++ b/cpp/config/suites/c/correctness @@ -7,7 +7,7 @@ + semmlecode-cpp-queries/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/ImplicitDowncastFromBitfield.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions - # Consistent Use + # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCallOnResult.ql: /Correctness/Consistent Use @@ -15,6 +15,7 @@ + semmlecode-cpp-queries/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/CompareWhereAssignMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Likely Typos/FutileParams.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors diff --git a/cpp/config/suites/cpp/correctness b/cpp/config/suites/cpp/correctness index ceb15f55260..00ad7a1ad07 100644 --- a/cpp/config/suites/cpp/correctness +++ b/cpp/config/suites/cpp/correctness @@ -8,7 +8,7 @@ + semmlecode-cpp-queries/Likely Bugs/Conversion/ImplicitDowncastFromBitfield.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions - # Consistent Use + # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCheckReturnNull.ql: /Correctness/Consistent Use + semmlecode-cpp-queries/Likely Bugs/InconsistentCallOnResult.ql: /Correctness/Consistent Use @@ -16,6 +16,7 @@ + semmlecode-cpp-queries/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/CompareWhereAssignMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Likely Typos/FutileParams.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors diff --git a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql index 9cfa9315486..af258c03b9f 100644 --- a/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql +++ b/cpp/ql/src/Likely Bugs/Conversion/ArrayArgSizeMismatch.ql @@ -5,9 +5,11 @@ * @kind problem * @id cpp/array-arg-size-mismatch * @problem.severity warning + * @precision high * @tags reliability */ import cpp +import semmle.code.cpp.commons.Buffer from Function f, FunctionCall c, int i, ArrayType argType, ArrayType paramType, int a, int b where f = c.getTarget() and @@ -17,6 +19,7 @@ where f = c.getTarget() and b = paramType.getArraySize() and argType.getBaseType().getSize() = paramType.getBaseType().getSize() and a < b and + not memberMayBeVarSize(_, c.getArgument(i).(VariableAccess).getTarget()) and // filter out results for inconsistent declarations strictcount(f.getParameter(i).getType().getSize()) = 1 select c.getArgument(i), "Array of size " + a + diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c new file mode 100644 index 00000000000..1a827a6c90a --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c @@ -0,0 +1,11 @@ +void no_argument(); + +void one_argument(int x); + +void calls() { + no_argument(1) // BAD: `no_argument` will accept and ignore the argument + + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + no_argument(); // GOOD: `no_argument` has not been passed an argument +} \ No newline at end of file diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp new file mode 100644 index 00000000000..6c4fc404fea --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp @@ -0,0 +1,29 @@ + + + + + +

A function is called with arguments despite having an empty parameter list. This may indicate +that the incorrect function is being called, or that the author misunderstood the function.

+ +

In C, a function declared with an empty parameter list `()` is considered to have an unknown +parameter list, and therefore can be called with any set of arguments. To declare a function +which takes no arguments, you must use `(void)` as the parameter list in any forward declarations. +In C++, either style of declaration indicates that the function accepts no arguments.

+ +
+ +

Call the function without arguments, or call a different function that expects the arguments +being passed.

+ +
+ + + + + +
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql new file mode 100644 index 00000000000..bb5a99a69bc --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql @@ -0,0 +1,22 @@ +/** + * @name Non-empty call to function declared without parameters + * @description A call to a function declared without parameters has arguments, which may indicate + * that the code does not follow the author's intent. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/futile-params + * @tags correctness + * maintainability + */ + +import cpp + +from Function f, FunctionCall fc +where fc.getTarget() = f + and f.getNumberOfParameters() = 0 + and not f.isVarargs() + and fc.getNumberOfArguments() != 0 + and not f instanceof BuiltInFunction + and exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit()) +select fc, "This call has arguments, but $@ is not declared with any parameters.", f, f.toString() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected new file mode 100644 index 00000000000..d3e6062f627 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.expected @@ -0,0 +1 @@ +| test.cpp:24:4:24:7 | arr3 | Array of size 3 passed to $@ which expects an array of size 4. | test.cpp:8:6:8:6 | g | g | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref new file mode 100644 index 00000000000..2e2747737a9 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/ArrayArgSizeMismatch.qlref @@ -0,0 +1 @@ +Likely Bugs/Conversion/ArrayArgSizeMismatch.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp new file mode 100644 index 00000000000..52b8f41bf22 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Conversion/ArrayArgSizeMismatch/test.cpp @@ -0,0 +1,49 @@ + +typedef unsigned long size_t; +void *malloc(size_t size); + +#define NUM (4) + +void f(int *vs); +void g(int vs[4]); +void h(float fs[NUM]); + +struct myStruct +{ + unsigned int num; + float data[0]; +}; + +void test(float f3[3], float f4[4], float f5[5], float *fp) +{ + int arr3[3], arr4[4], arr5[5]; + + f(arr3); // GOOD + f(arr4); // GOOD + f(arr5); // GOOD + g(arr3); // BAD + g(arr4); // GOOD + g(arr5); // GOOD + + h(f3); // BAD [NOT DETECTED] + h(f4); // GOOD + h(f5); // GOOD + h(fp); // GOOD + + { + // variable size struct + myStruct *ms; + + ms = (myStruct *)malloc(sizeof(myStruct) + (4 * sizeof(float))); + ms->num = 4; + ms->data[0] = ms->data[1] = ms->data[2] = ms->data[3] = 0; + h(ms->data); // GOOD + } + + { + // char array + char ca[4 * sizeof(int)]; + + g((int *)ca); // GOOD + } +}; diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected new file mode 100644 index 00000000000..d6dc2222be4 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected @@ -0,0 +1,3 @@ +| test.c:8:3:8:16 | call to declared_empty | This call has arguments, but $@ is not declared with any parameters. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:14:3:14:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:25:6:25:22 | not_yet_declared1 | not_yet_declared1 | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref new file mode 100644 index 00000000000..f6dbe907dc5 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref @@ -0,0 +1 @@ +Likely Bugs/Likely Typos/FutileParams.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c new file mode 100644 index 00000000000..9589d2a9ffc --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c @@ -0,0 +1,29 @@ +void declared_empty(); +void declared_void(void); +void declared_with(int); +void declared_empty_defined_with(); + +void test() { + declared_empty(); // GOOD + declared_empty(1); // BAD + declared_void(); // GOOD + declared_with(1); // GOOD + + undeclared(1); // GOOD + + not_yet_declared1(1); // BAD + not_yet_declared2(1); // GOOD + + declared_empty_defined_with(); // BAD [NOT DETECTED] + declared_empty_defined_with(1); // GOOD + + int x; + declared_empty_defined_with(&x); // BAD [NOT DETECTED] + declared_empty_defined_with(x, x); // BAD [NOT DETECTED] +} + +void not_yet_declared1(); +void not_yet_declared2(int); +void declared_empty_defined_with(int x) { + // do nothing +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp new file mode 100644 index 00000000000..855fdaea3fd --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp @@ -0,0 +1,8 @@ +void cpp_varargs(...); +void bar(); + +void test() { + cpp_varargs(); // GOOD + cpp_varargs(1); // GOOD + __builtin_constant_p("something"); // GOOD: builtin +} \ No newline at end of file diff --git a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs index 2b655310e09..de22028fd96 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Tests/BuildScripts.cs @@ -855,6 +855,7 @@ namespace Semmle.Extraction.Tests Actions.RunProcess[@"curl -sO https://dot.net/v1/dotnet-install.sh"] = 0; Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; + Actions.RunProcess[@"rm dotnet-install.sh"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet clean test.csproj"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet restore test.csproj"] = 0; @@ -879,7 +880,7 @@ namespace Semmle.Extraction.Tests Actions.LoadXml["test.csproj"] = xml; var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 10); + TestAutobuilderScript(autobuilder, 0, 11); } [Fact] @@ -890,6 +891,7 @@ namespace Semmle.Extraction.Tests Actions.RunProcess[@"curl -sO https://dot.net/v1/dotnet-install.sh"] = 0; Actions.RunProcess[@"chmod u+x dotnet-install.sh"] = 0; Actions.RunProcess[@"./dotnet-install.sh --channel release --version 2.1.3 --install-dir C:\Project/.dotnet"] = 0; + Actions.RunProcess[@"rm dotnet-install.sh"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet --info"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet clean test.csproj"] = 0; Actions.RunProcess[@"C:\Project/.dotnet/dotnet restore test.csproj"] = 0; @@ -914,7 +916,7 @@ namespace Semmle.Extraction.Tests Actions.LoadXml["test.csproj"] = xml; var autobuilder = CreateAutoBuilder("csharp", false, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 10); + TestAutobuilderScript(autobuilder, 0, 11); } [Fact] @@ -923,6 +925,7 @@ namespace Semmle.Extraction.Tests Actions.RunProcess["cmd.exe /C dotnet --list-sdks"] = 0; Actions.RunProcessOut["cmd.exe /C dotnet --list-sdks"] = "2.1.3 [C:\\Program Files\\dotnet\\sdks]\n2.1.4 [C:\\Program Files\\dotnet\\sdks]"; Actions.RunProcess[@"cmd.exe /C powershell -NoProfile -ExecutionPolicy unrestricted -file C:\Project\install-dotnet.ps1 -Version 2.1.3 -InstallDir C:\Project\.dotnet"] = 0; + Actions.RunProcess[@"cmd.exe /C del C:\Project\install-dotnet.ps1"] = 0; Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet --info"] = 0; Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet clean test.csproj"] = 0; Actions.RunProcess[@"cmd.exe /C C:\Project\.dotnet\dotnet restore test.csproj"] = 0; @@ -947,7 +950,7 @@ namespace Semmle.Extraction.Tests Actions.LoadXml["test.csproj"] = xml; var autobuilder = CreateAutoBuilder("csharp", true, dotnetVersion: "2.1.3"); - TestAutobuilderScript(autobuilder, 0, 8); + TestAutobuilderScript(autobuilder, 0, 9); } [Fact] diff --git a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs b/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs index 9cce54ab50e..f3e95921a44 100644 --- a/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs +++ b/csharp/autobuilder/Semmle.Autobuild/DotNetRule.cs @@ -185,7 +185,12 @@ Invoke-Command -ScriptBlock $ScriptBlock"; Argument(version). Argument("-InstallDir"). Argument(path); - return install.Script; + + var removeScript = new CommandBuilder(builder.Actions). + RunCommand("del"). + Argument(psScriptFile); + + return install.Script & BuildScript.Try(removeScript.Script); } else { @@ -208,7 +213,11 @@ Invoke-Command -ScriptBlock $ScriptBlock"; Argument("--install-dir"). Argument(path); - return curl.Script & chmod.Script & install.Script; + var removeScript = new CommandBuilder(builder.Actions). + RunCommand("rm"). + Argument("dotnet-install.sh"); + + return curl.Script & chmod.Script & install.Script & BuildScript.Try(removeScript.Script); } }); } diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index b01977a369a..24ccfb7d1f0 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -39,6 +39,12 @@ class AssignableMemberAccess extends MemberAccess, AssignableAccess { override AssignableMember getTarget() { result = AssignableAccess.super.getTarget() } } +private predicate nameOfChild(NameOfExpr noe, Expr child) { + child = noe + or + exists(Expr mid | nameOfChild(noe, mid) | child = mid.getAChildExpr()) +} + /** * An access to an assignable that reads the underlying value. Either a * variable read (`VariableRead`), a property read (`PropertyRead`), an @@ -67,7 +73,7 @@ class AssignableRead extends AssignableAccess { or this = any(AssignableDefinitions::AddressOfDefinition def).getTargetAccess() ) and - not this = any(NameOfExpr noe).getAChildExpr*() + not nameOfChild(_, this) } /** @@ -696,6 +702,9 @@ module AssignableDefinitions { IsPatternDefinition() { this = TIsPatternDefinition(ipe) } + /** Gets the underlying `is` expression. */ + IsPatternExpr getIsPatternExpr() { result = ipe } + /** Gets the underlying local variable declaration. */ LocalVariableDeclExpr getDeclaration() { result = ipe.getVariableDeclExpr() } @@ -721,6 +730,9 @@ module AssignableDefinitions { TypeCasePatternDefinition() { this = TTypeCasePatternDefinition(tc) } + /** Gets the underlying `case` statement. */ + TypeCase getTypeCase() { result = tc } + /** Gets the underlying local variable declaration. */ LocalVariableDeclExpr getDeclaration() { result = tc.getVariableDeclExpr() } diff --git a/csharp/ql/src/semmle/code/csharp/Stmt.qll b/csharp/ql/src/semmle/code/csharp/Stmt.qll index 51f1ccaefb0..2adbb38902b 100644 --- a/csharp/ql/src/semmle/code/csharp/Stmt.qll +++ b/csharp/ql/src/semmle/code/csharp/Stmt.qll @@ -262,6 +262,9 @@ class CaseStmt extends Stmt, @case { * ``` */ Expr getCondition() { result = this.getChild(2) } + + /** Gets the `switch` statement that this `case` statement belongs to. */ + SwitchStmt getSwitchStmt() { result.getACase() = this } } /** diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll index 64bdf961282..efb99dc6de8 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/ControlFlowGraph.qll @@ -867,6 +867,8 @@ module ControlFlow { * pre-order. */ private module Successor { + private import semmle.code.csharp.ExprOrStmtParent + /** * A control flow element where the children are evaluated following a * standard left-to-right evaluation. The actual evaluation order is @@ -2436,11 +2438,16 @@ module ControlFlow { * Gets the control flow element that is first executed when entering * callable `c`. */ - ControlFlowElement succEntry(Callable c) { - if exists(c.(Constructor).getInitializer()) then - result = first(c.(Constructor).getInitializer()) - else - result = first(c.getBody()) + ControlFlowElement succEntry(@top_level_exprorstmt_parent p) { + p = any(Callable c | + if exists(c.(Constructor).getInitializer()) then + result = first(c.(Constructor).getInitializer()) + else + result = first(c.getBody()) + ) + or + expr_parent_top_level_adjusted(any(Expr e | result = first(e)), _, p) and + not p instanceof Callable } /** @@ -3807,8 +3814,8 @@ module ControlFlow { * Holds if `succ` with splits `succSplits` is the first element that is executed * when entering callable `pred`. */ - pragma [noinline] - predicate succEntrySplits(Callable pred, ControlFlowElement succ, Splits succSplits, SuccessorType t) { + pragma[noinline] + predicate succEntrySplits(@top_level_exprorstmt_parent pred, ControlFlowElement succ, Splits succSplits, SuccessorType t) { succ = succEntry(pred) and t instanceof NormalSuccessor and succSplits = TSplitsNil() // initially no splits diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index a1c112c8057..856a45ad711 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -417,7 +417,9 @@ class AccessOrCallExpr extends Expr { * An expression can have more than one SSA qualifier in the presence * of control flow splitting. */ - Ssa::Definition getAnSsaQualifier() { result = getAnSsaQualifier(this) } + Ssa::Definition getAnSsaQualifier(ControlFlow::Node cfn) { + result = getAnSsaQualifier(this, cfn) + } } private Declaration getDeclarationTarget(Expr e) { @@ -425,18 +427,20 @@ private Declaration getDeclarationTarget(Expr e) { result = e.(Call).getTarget() } -private Ssa::Definition getAnSsaQualifier(Expr e) { - e = getATrackedAccess(result) +private Ssa::Definition getAnSsaQualifier(Expr e, ControlFlow::Node cfn) { + e = getATrackedAccess(result, cfn) or - not e = getATrackedAccess(_) and - result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier()) + not e = getATrackedAccess(_, _) and + result = getAnSsaQualifier(e.(QualifiableExpr).getQualifier(), cfn) } -private AssignableAccess getATrackedAccess(Ssa::Definition def) { +private AssignableAccess getATrackedAccess(Ssa::Definition def, ControlFlow::Node cfn) { ( - result = def.getARead() + result = def.getAReadAtNode(cfn) or - result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() + result = def.(Ssa::ExplicitDefinition).getADefinition().getTargetAccess() and + result.getAControlFlowNode() = cfn and + cfn.getBasicBlock() = def.getBasicBlock() ) and not def instanceof Ssa::ImplicitUntrackedDefinition } @@ -483,7 +487,7 @@ class GuardedExpr extends AccessOrCallExpr { private AccessOrCallExpr sub0; private AbstractValue v0; - GuardedExpr() { isGuardedBy(this, g, sub0, v0) } + GuardedExpr() { isGuardedByExpr(this, g, sub0, v0) } /** * Gets an expression that guards this expression. That is, this expression is @@ -525,6 +529,115 @@ class GuardedExpr extends AccessOrCallExpr { } } +/** + * A guarded control flow node. A guarded control flow node is like a guarded + * expression (`GuardedExpr`), except control flow graph splitting is taken + * into account. That is, one control flow node belonging to an expression may + * be guarded, while another split need not be guarded: + * + * ``` + * if (b) + * if (x == null) + * return; + * x.ToString(); + * if (b) + * ... + * ``` + * + * In the example above, the node for `x.ToString()` is null-guarded in the + * split `b == true`, but not in the split `b == false`. + */ +class GuardedControlFlowNode extends ControlFlow::Nodes::ElementNode { + private Guard g; + private AccessOrCallExpr sub0; + private AbstractValue v0; + + GuardedControlFlowNode() { isGuardedByNode(this, g, sub0, v0) } + + /** + * Gets an expression that guards this control flow node. That is, this control + * flow node is only reached when the returned expression has abstract value `v`. + * + * The expression `sub` is a sub expression of the guarding expression that is + * structurally equal to the expression belonging to this control flow node. + * + * In case this control flow node or `sub` accesses an SSA variable in its + * left-most qualifier, then so must the other (accessing the same SSA + * variable). + */ + Expr getAGuard(Expr sub, AbstractValue v) { + result = g and + sub = sub0 and + v = v0 + } + + /** + * Holds if this control flow node must have abstract value `v`. That is, this + * control flow node is guarded by a structurally equal expression having + * abstract value `v`. + */ + predicate mustHaveValue(AbstractValue v) { + exists(Expr e | e = this.getAGuard(e, v)) + } +} + +/** + * A guarded data flow node. A guarded data flow node is like a guarded expression + * (`GuardedExpr`), except control flow graph splitting is taken into account. That + * is, one data flow node belonging to an expression may be guarded, while another + * split need not be guarded: + * + * ``` + * if (b) + * if (x == null) + * return; + * x.ToString(); + * if (b) + * ... + * ``` + * + * In the example above, the node for `x.ToString()` is null-guarded in the + * split `b == true`, but not in the split `b == false`. + */ +class GuardedDataFlowNode extends DataFlow::ExprNode { + private Guard g; + private AccessOrCallExpr sub0; + private AbstractValue v0; + + GuardedDataFlowNode() { + exists(ControlFlow::Nodes::ElementNode cfn | + exists(this.getExprAtNode(cfn)) | + isGuardedByNode(cfn, g, sub0, v0) + ) + } + + /** + * Gets an expression that guards this data flow node. That is, this data flow + * node is only reached when the returned expression has abstract value `v`. + * + * The expression `sub` is a sub expression of the guarding expression that is + * structurally equal to the expression belonging to this data flow node. + * + * In case this data flow node or `sub` accesses an SSA variable in its + * left-most qualifier, then so must the other (accessing the same SSA + * variable). + */ + Expr getAGuard(Expr sub, AbstractValue v) { + result = g and + sub = sub0 and + v = v0 + } + + /** + * Holds if this data flow node must have abstract value `v`. That is, this + * data flow node is guarded by a structurally equal expression having + * abstract value `v`. + */ + predicate mustHaveValue(AbstractValue v) { + exists(Expr e | e = this.getAGuard(e, v)) + } +} + /** An expression guarded by a `null` check. */ class NullGuardedExpr extends GuardedExpr { NullGuardedExpr() { @@ -532,6 +645,13 @@ class NullGuardedExpr extends GuardedExpr { } } +/** A data flow node guarded by a `null` check. */ +class NullGuardedDataFlowNode extends GuardedDataFlowNode { + NullGuardedDataFlowNode() { + this.mustHaveValue(any(NullValue v | not v.isNull())) + } +} + /** INTERNAL: Do not use. */ module Internal { private import ControlFlow::Internal @@ -653,7 +773,7 @@ module Internal { * Holds if control flow node `cfn` only is reached when this guard evaluates to `v`, * because of an assertion. */ - private predicate assertionControlsNode(ControlFlow::Node cfn, AbstractValue v) { + predicate assertionControlsNode(ControlFlow::Node cfn, AbstractValue v) { exists(Assertion a, Guard g, AbstractValue v0 | asserts(a, g, v0) and impliesSteps(g, v0, this, v) @@ -1097,17 +1217,17 @@ module Internal { private cached module Cached { pragma[noinline] - private predicate isGuardedBy0(ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + private predicate isGuardedByNode0(ControlFlow::Node cfn, AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { cfn = guarded.getAControlFlowNode() and g.controls(cfn.getBasicBlock(), v) and exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded)) } pragma[noinline] - private predicate isGuardedBy1(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + private predicate isGuardedByExpr1(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { forex(ControlFlow::Node cfn | cfn = guarded.getAControlFlowNode() | - isGuardedBy0(cfn, guarded, g, sub, v) + isGuardedByNode0(cfn, guarded, g, sub, v) ) or g.assertionControlsElement(guarded, v) and @@ -1115,12 +1235,33 @@ module Internal { } cached - predicate isGuardedBy(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { - isGuardedBy1(guarded, g, sub, v) and + predicate isGuardedByExpr(AccessOrCallExpr guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedByExpr1(guarded, g, sub, v) and sub = g.getAChildExpr*() and forall(Ssa::Definition def | - def = sub.getAnSsaQualifier() | - def = guarded.getAnSsaQualifier() + def = sub.getAnSsaQualifier(_) | + def = guarded.getAnSsaQualifier(_) + ) + } + + pragma[noinline] + private predicate isGuardedByNode1(ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedByNode0(guarded, _, g, sub, v) + or + g.assertionControlsNode(guarded, v) and + exists(ConditionOnExprComparisonConfig c | c.same(sub, guarded.getElement())) + } + + cached + predicate isGuardedByNode(ControlFlow::Nodes::ElementNode guarded, Guard g, AccessOrCallExpr sub, AbstractValue v) { + isGuardedByNode1(guarded, g, sub, v) and + sub = g.getAChildExpr*() and + forall(Ssa::Definition def | + def = sub.getAnSsaQualifier(_) | + exists(ControlFlow::Node cfn | + def = guarded.getElement().(AccessOrCallExpr).getAnSsaQualifier(cfn) | + cfn.getBasicBlock() = guarded.getBasicBlock() + ) ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll index 2af9d3d3e27..b8acdf28275 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll @@ -21,6 +21,12 @@ module DataFlow { /** Gets the expression corresponding to this node, if any. */ DotNet::Expr asExpr() { result = this.(ExprNode).getExpr() } + /** Gets the expression corresponding to this node, at control flow node `cfn`, if any. */ + Expr asExprAtNode(ControlFlow::Nodes::ElementNode cfn) { + this = TExprNode(cfn) and + result = cfn.getElement() + } + /** Gets the parameter corresponding to this node, if any. */ DotNet::Parameter asParameter() { result = this.(ParameterNode).getParameter() } @@ -41,30 +47,47 @@ module DataFlow { /** * An expression, viewed as a node in a data flow graph. */ - class ExprNode extends Node, TExprNode { - DotNet::Expr expr; - - ExprNode() { this = TExprNode(expr) } + class ExprNode extends Node { + ExprNode() { this = TExprNode(_) or this = TCilExprNode(_) } /** Gets the expression corresponding to this node. */ - DotNet::Expr getExpr() { result = expr } + DotNet::Expr getExpr() { + result = this.getExprAtNode(_) + or + this = TCilExprNode(result) + } - override DotNet::Type getType() { result = expr.getType() } + /** Gets the expression corresponding to this node, at control flow node `cfn`. */ + Expr getExprAtNode(ControlFlow::Nodes::ElementNode cfn) { + this = TExprNode(cfn) and + result = cfn.getElement() + } - override DotNet::Callable getEnclosingCallable() { result = expr.getEnclosingCallable() } + override DotNet::Type getType() { result = this.getExpr().getType() } + + override DotNet::Callable getEnclosingCallable() { result = this.getExpr().getEnclosingCallable() } override string toString() { - result = expr.(Expr).toString() + exists(ControlFlow::Nodes::ElementNode cfn | + this = TExprNode(cfn) | + result = cfn.toString() + ) or - expr instanceof CIL::Expr and + this = TCilExprNode(_) and result = "CIL expression" } override Location getLocation() { - result = expr.(Expr).getLocation() + exists(ControlFlow::Nodes::ElementNode cfn | + this = TExprNode(cfn) | + result = cfn.getLocation() + ) or result.getFile().isPdbSourceFile() and - result = expr.(CIL::Expr).getALocation() + exists(CIL::Expr e | + this = TCilExprNode(e) | + result = e.getALocation() + ) } } @@ -83,9 +106,7 @@ module DataFlow { DotNet::Parameter getParameter() { none() } } - /** - * Gets the node corresponding to expression `e`. - */ + /** Gets a node corresponding to expression `e`. */ ExprNode exprNode(DotNet::Expr e) { result.getExpr() = e } /** @@ -258,9 +279,7 @@ module DataFlow { } } - /** - * INTERNAL: Do not use. - */ + /** INTERNAL: Do not use. */ module Internal { private import semmle.code.csharp.dataflow.DelegateDataFlow private import semmle.code.csharp.dispatch.Dispatch @@ -473,6 +492,9 @@ module DataFlow { /** Gets the context corresponding to this argument node. */ bindingset [config] abstract ArgumentContext getContext(Configuration config); + + /** Holds if this argument node does not have an associated control flow node. */ + abstract predicate hasNoControlFlowNode(); } /** A data flow node that represents an explicit call argument. */ @@ -511,6 +533,11 @@ module DataFlow { override ExplicitArgumentContext getContext(Configuration config) { result.getCallContext() = this.getArgumentCallContext(config) } + + override predicate hasNoControlFlowNode() { + this.asExpr() instanceof CIL::Expr or + this instanceof ImplicitDelegateCallNode + } } /** @@ -558,6 +585,8 @@ module DataFlow { exists(config) // eliminate warning } + override predicate hasNoControlFlowNode() { any() } + override Type getType() { result = v.getType() } override Callable getEnclosingCallable() { result = c.getEnclosingCallable() } @@ -699,9 +728,180 @@ module DataFlow { } /** - * Provides predicates related to local data flow. + * A helper class for defining expression-based data flow steps, while properly + * taking control flow into account. */ + abstract class ExprStepConfiguration extends string { + bindingset[this] + ExprStepConfiguration() { any() } + + /** + * Holds if data can flow from expression `exprFrom` to expression `exprTo`, + * but only by following control flow successors (resp. predecessors, as + * specified by `isSuccesor`) inside the scope `scope`. The Boolean `exactScope` + * indicates whether a transitive child of `scope` is allowed + * (`exactScope = false`). + */ + predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { none() } + + /** + * Holds if data can flow from expression `exprFrom` to definition `defTo`, + * but only by following control flow successors (resp. predecessors, as + * specified by `isSuccesor`) inside the scope `scope`. The Bolean `exactScope` + * indicates whether a transitive child of `scope` is allowed (`exactScope = false`). + */ + predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { none() } + + private predicate reachesBasicBlockExprRec(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + exists(ControlFlow::BasicBlock mid | + this.reachesBasicBlockExpr(exprFrom, exprTo, scope, exactScope, isSuccessor, cfnFrom, mid) | + isSuccessor = true and + bb = mid.getASuccessor() + or + isSuccessor = false and + bb = mid.getAPredecessor() + ) + } + + pragma[nomagic] + private predicate reachesBasicBlockExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + this.stepsToExpr(exprFrom, exprTo, scope, exactScope, isSuccessor) and + cfnFrom = exprFrom.getAControlFlowNode() and + bb = cfnFrom.getBasicBlock() + or + exists(ControlFlowElement scope0, boolean exactScope0 | + this.reachesBasicBlockExprRec(exprFrom, exprTo, scope0, exactScope0, isSuccessor, cfnFrom, bb) and + this.stepsToExpr(exprFrom, exprTo, scope, exactScope, isSuccessor) + | + exactScope0 = false and + bb.getANode().getElement() = scope0.getAChild*() + or + exactScope0 = true and + bb.getANode().getElement() = scope0 + ) + } + + private predicate reachesBasicBlockDefinitionRec(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + exists(ControlFlow::BasicBlock mid | + this.reachesBasicBlockDefinition(exprFrom, defTo, scope, exactScope, isSuccessor, cfnFrom, mid) | + isSuccessor = true and + bb = mid.getASuccessor() + or + isSuccessor = false and + bb = mid.getAPredecessor() + ) + } + + + pragma[nomagic] + private predicate reachesBasicBlockDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb) { + this.stepsToDefinition(exprFrom, defTo, scope, exactScope, isSuccessor) and + cfnFrom = exprFrom.getAControlFlowNode() and + bb = cfnFrom.getBasicBlock() + or + exists(ControlFlowElement scope0, boolean exactScope0 | + this.reachesBasicBlockDefinitionRec(exprFrom, defTo, scope0, exactScope0, isSuccessor, cfnFrom, bb) and + this.stepsToDefinition(exprFrom, defTo, scope, exactScope, isSuccessor) + | + exactScope0 = false and + bb.getANode().getElement() = scope0.getAChild*() + or + exactScope0 = true and + bb.getANode().getElement() = scope0 + ) + } + + private predicate hasExprStep(ExprNode nodeFrom, ExprNode nodeTo) { + exists(Expr exprFrom, Expr exprTo, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb | + this.reachesBasicBlockExpr(exprFrom, exprTo, _, _, _, cfnFrom, bb) | + exprFrom = nodeFrom.asExprAtNode(cfnFrom) and + exprTo = nodeTo.asExprAtNode(bb.getANode()) + ) + } + + private predicate hasSsaDefinitionStep(ExprNode nodeFrom, SsaDefinitionNode nodeTo) { + exists(Expr exprFrom, AssignableDefinition defTo, Ssa::ExplicitDefinition ssaDef, ControlFlow::Nodes::ElementNode cfnFrom, ControlFlow::BasicBlock bb | + this.reachesBasicBlockDefinition(exprFrom, defTo, _, _, _, cfnFrom, bb) | + exprFrom = nodeFrom.asExprAtNode(cfnFrom) and + ssaDef.getADefinition() = defTo and + ssaDef.getBasicBlock() = bb and + nodeTo.getDefinition() = ssaDef + ) + } + + /** + * Holds if `stepsTo(Expr|SsaDefintion)()` induce a data flow step from + * `nodeFrom` to `nodeTo`. + */ + predicate hasStep(ExprNode nodeFrom, Node nodeTo) { + this.hasExprStep(nodeFrom, nodeTo) or + this.hasSsaDefinitionStep(nodeFrom, nodeTo) + } + } + + /** Provides predicates related to local data flow. */ module LocalFlow { + private class LocalExprStepConfiguration extends ExprStepConfiguration { + LocalExprStepConfiguration() { this = "LocalExprStepConfiguration" } + + override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + exactScope = false and + ( + // Flow using library code + libraryFlow(exprFrom, exprTo, scope, isSuccessor, true) + or + exprFrom = exprTo.(ParenthesizedExpr).getExpr() and + scope = exprTo and + isSuccessor = true + or + exprTo = any(ConditionalExpr ce | + exprFrom = ce.getThen() or + exprFrom = ce.getElse() + ) and + scope = exprTo and + isSuccessor = false + or + exprFrom = exprTo.(Cast).getExpr() and + scope = exprTo and + isSuccessor = true + or + exprFrom = exprTo.(AwaitExpr).getExpr() and + scope = exprTo and + isSuccessor = true + or + // An `=` expression, where the result of the expression is used + exprTo = any(AssignExpr ae | + ae.getParent() instanceof Expr and + exprFrom = ae.getRValue() + ) and + scope = exprTo and + isSuccessor = true + ) + } + + override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition def, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + // Flow from source to definition + exactScope = false and + def.getSource() = exprFrom and + ( + scope = def.getExpr() and + isSuccessor = true + or + scope = def.(AssignableDefinitions::IsPatternDefinition).getIsPatternExpr() and + isSuccessor = false + or + exists(SwitchStmt ss | + ss = def.(AssignableDefinitions::TypeCasePatternDefinition).getTypeCase().getSwitchStmt() and + isSuccessor = true + | + scope = ss.getCondition() + or + scope = ss.getACase() + ) + ) + } + } + /** * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * (intra-procedural) step. @@ -709,18 +909,20 @@ module DataFlow { cached predicate step(Node nodeFrom, Node nodeTo) { forceCachingInSameStage() and - localFlowStepExpr(nodeFrom.asExpr(), nodeTo.asExpr()) - or - // Flow from source to SSA definition - exists(Ssa::ExplicitDefinition def | - def.getADefinition().getSource() = nodeFrom.asExpr() | - nodeTo.(SsaDefinitionNode).getDefinition() = def - ) + TaintTracking::Internal::Cached::forceCachingInSameStage() and + any(LocalExprStepConfiguration x).hasStep(nodeFrom, nodeTo) or // Flow from SSA definition to first read - exists(Ssa::Definition def | + exists(Ssa::Definition def, ControlFlow::Node cfn | def = nodeFrom.(SsaDefinitionNode).getDefinition() | - nodeTo.asExpr() = def.getAFirstRead() + nodeTo.asExprAtNode(cfn) = def.getAFirstReadAtNode(cfn) + ) + or + // Flow from read to next read + exists(ControlFlow::Node cfnFrom, ControlFlow::Node cfnTo | + Ssa::Internal::adjacentReadPairSameVar(cfnFrom, cfnTo) | + nodeFrom = TExprNode(cfnFrom) and + nodeTo = TExprNode(cfnTo) ) or // Flow into SSA pseudo definition @@ -779,9 +981,9 @@ module DataFlow { def = nodeFrom.(SsaDefinitionNode).getDefinition() and not exists(def.getARead()) or - exists(AssignableRead read | - read = nodeFrom.asExpr() | - def.getALastRead() = read + exists(AssignableRead read, ControlFlow::Node cfn | + read = nodeFrom.asExprAtNode(cfn) | + def.getALastReadAtNode(cfn) = read ) } @@ -794,34 +996,30 @@ module DataFlow { ) } - private predicate localFlowStepExpr(Expr exprFrom, Expr exprTo) { - // Flow using library code - libraryFlow(exprFrom, exprTo, true) + private Expr getALibraryFlowParent(Expr exprFrom, Expr exprTo, boolean preservesValue) { + libraryFlow(exprFrom, exprTo, preservesValue) and + result = exprFrom or - // Flow from read to next read - exprTo = exprFrom.(AssignableRead).getANextRead() - or - exprFrom = exprTo.(ParenthesizedExpr).getExpr() - or - exprTo = any(ConditionalExpr ce | - exprFrom = ce.getThen() or - exprFrom = ce.getElse() - ) - or - exprFrom = exprTo.(Cast).getExpr() - or - exprFrom = exprTo.(AwaitExpr).getExpr() - or - // An `=` expression, where the result of the expression is used - exprTo = any(AssignExpr ae | - ae.getParent() instanceof Expr and - exprFrom = ae.getRValue() + exists(Expr mid | + mid = getALibraryFlowParent(exprFrom, exprTo, preservesValue) | + result.getAChildExpr() = mid and + not mid.getAChildExpr*() = exprTo ) } + predicate libraryFlow(Expr exprFrom, Expr exprTo, Expr scope, boolean isSuccessor, boolean preservesValue) { + // To not pollute the definitions in `LibraryTypeDataFlow.qll` with syntactic scope, + // simply use the nearest common parent expression for `exprFrom` and `exprTo` + scope = getALibraryFlowParent(exprFrom, exprTo, preservesValue) and + scope.getAChildExpr*() = exprTo and + // Similarly, for simplicity allow following both forwards and backwards edges from + // `exprFrom` to `exprTo` + (isSuccessor = true or isSuccessor = false) + } + predicate localFlowStepNoConfig(Node pred, Node succ) { localFlowStep(pred, succ) or - flowThroughCallableLibraryOutRef(_, pred.asExpr(), succ, true) + flowThroughCallableLibraryOutRef(_, pred, succ, true) } /** @@ -1135,7 +1333,9 @@ module DataFlow { cached predicate forceCachingInSameStage() { any() } cached newtype TNode = - TExprNode(DotNet::Expr e) + TExprNode(ControlFlow::Nodes::ElementNode cfn) { + cfn.getElement() instanceof Expr + } or TSsaDefinitionNode(Ssa::Definition def) or @@ -1143,6 +1343,8 @@ module DataFlow { p.getMethod().hasBody() } or + TCilExprNode(CIL::Expr e) + or TImplicitDelegateCallNode(DelegateArgumentToLibraryCallable arg) or TImplicitCapturedArgumentNode(Call c, LocalScopeVariable v) { @@ -1554,8 +1756,8 @@ module DataFlow { * Holds if data may flow from argument `mid` of a call, back out from the * call to `out`. The context after the call is `ctx`. */ - pragma [noinline] - private predicate flowThroughCallable(FlowGraphNode mid, OutNode out, Context ctx) { + pragma[nomagic] + private predicate flowThroughCallable0(FlowGraphNode mid, OutNode out, Context ctx) { exists(CallNode call, ParameterNode p, ArgumentContext innerctx, CallContext cc | flowIntoCallable(mid, p, innerctx) and paramFlowsThrough(call, p, out, innerctx, cc) | @@ -1579,6 +1781,44 @@ module DataFlow { ) } + private predicate flowThroughCallable1Scope(OutNode out, Expr e) { + flowThroughCallable0(_, out, _) and + e = out.asExpr().(Expr).getAChildExpr*() + } + + pragma[nomagic] + private predicate flowThroughCallable1(FlowGraphNode mid, OutNode out, ControlFlow::Nodes::ElementNode cfn, Context ctx) { + flowThroughCallable0(mid, out, ctx) and + exists(mid.getNode().asExprAtNode(cfn)) + or + exists(ControlFlow::Nodes::ElementNode cfnMid | + flowThroughCallable1(mid, out, cfnMid, ctx) | + cfn = cfnMid.getASuccessor() and + flowThroughCallable1Scope(out, cfn.getElement()) + ) + } + + /** + * Holds if data may flow from argument `mid` of a call, back out from the + * call to `out`. The context after the call is `ctx`. + */ + pragma[nomagic] + private predicate flowThroughCallable(FlowGraphNode mid, OutNode out, Context ctx) { + // If both `mid` and `out` have associated control flow nodes, the latter + // must be reachable from the former + exists(ControlFlow::Node cfn | + flowThroughCallable1(mid, out, cfn, ctx) | + exists(out.asExprAtNode(cfn)) + ) + or + flowThroughCallable0(mid, out, ctx) and + ( + mid.getNode().(ArgumentNode).hasNoControlFlowNode() + or + not out.asExpr() instanceof Expr + ) + } + /** * Holds if data can flow (inter-procedurally) from `source` to `sink`. * @@ -1592,6 +1832,23 @@ module DataFlow { flowsink.getNode() = sink } + private class FlowThroughCallableLibraryOutRefStepConfiguration extends ExprStepConfiguration { + FlowThroughCallableLibraryOutRefStepConfiguration() { + this = "FlowThroughCallableLibraryOutRefStepConfiguration" + } + + override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + exists(MethodCall mc, Parameter outRef | + libraryFlowOutRef(mc, exprFrom, outRef, _) | + defTo.getTargetAccess() = mc.getArgumentForParameter(outRef) and + defTo instanceof AssignableDefinitions::OutRefDefinition and + scope = mc and + isSuccessor = true and + exactScope = false + ) + } + } + /** * Holds if `arg` is an argument of the method call `mc`, where the target * of `mc` is a library callable that forwards `arg` to an `out`/`ref` argument @@ -1605,12 +1862,9 @@ module DataFlow { * `mc = Int32.TryParse("42", out i)`, `arg = "42"`, and `node` is the access * to `i` in `out i`. */ - predicate flowThroughCallableLibraryOutRef(MethodCall mc, Expr arg, SsaDefinitionNode node, boolean preservesValue) { - exists(Parameter outRef, AssignableDefinitions::OutRefDefinition def | - libraryFlowOutRef(mc, arg, outRef, preservesValue) | - def = node.getDefinition().(Ssa::ExplicitDefinition).getADefinition() and - def.getTargetAccess() = mc.getArgumentForParameter(outRef) - ) + predicate flowThroughCallableLibraryOutRef(MethodCall mc, ExprNode arg, SsaDefinitionNode node, boolean preservesValue) { + libraryFlowOutRef(mc, arg.getExpr(), _, preservesValue) and + any(FlowThroughCallableLibraryOutRefStepConfiguration x).hasStep(arg, node) } /** diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll b/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll index 53bf0189b0c..7959bd07cb6 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/TaintTracking.qll @@ -31,87 +31,6 @@ module TaintTracking { localAdditionalTaintStep(nodeFrom, nodeTo) } - private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { - result = node.asParameter() or - result = node.asExpr() - } - - private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) - } - - private cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - localAdditionalTaintStepExpr(nodeFrom.asExpr(), nodeTo.asExpr()) - or - DataFlow::Internal::flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) - or - // Taint from `foreach` expression - exists(ForeachStmt fs, AssignableDefinitions::LocalVariableDefinition def, Ssa::ExplicitDefinition ssaDef | - nodeFrom.asExpr() = fs.getIterableExpr() and - def.getTarget() = fs.getVariable() and - ssaDef.getADefinition() = def and - nodeTo.(DataFlow::Internal::SsaDefinitionNode).getDefinition() = ssaDef - ) - or - localTaintStepCil(nodeFrom, nodeTo) - } - - private predicate localAdditionalTaintStepExpr(Expr exprFrom, Expr exprTo) { - // Taint propagation using library code - libraryFlow(exprFrom, exprTo, false) - or - // Taint from assigned value to element qualifier (`x[i] = 0`) - exists(AssignExpr ae | - exprFrom = ae.getRValue() and - exprTo.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) - ) - or - // Taint from array initializer - exprFrom = exprTo.(ArrayCreation).getInitializer().getAnElement() - or - // Taint from object initializer - exists(ElementInitializer ei | - ei = exprTo.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and - exprFrom = ei.getArgument(ei.getNumberOfArguments() - 1) // assume the last argument is the value (i.e., not a key) - ) - or - // Taint from element qualifier - exprFrom = exprTo.(ElementAccess).getQualifier() - or - exprFrom = exprTo.(AddExpr).getAnOperand() - or - // A comparison expression where taint can flow from one of the - // operands if the other operand is a constant value. - exists(ComparisonTest ct, Expr other | - ct.getExpr() = exprTo and - exprFrom = ct.getAnArgument() and - other = ct.getAnArgument() and - other.stripCasts().hasValue() and - exprFrom != other - ) - or - exprFrom = exprTo.(LogicalOperation).getAnOperand() - or - // Taint from tuple argument - exprTo = any(TupleExpr te | - exprFrom = te.getAnArgument() and - te.isReadAccess() - ) - or - exprFrom = exprTo.(InterpolatedStringExpr).getAChild() - or - // Taint from tuple expression - exprTo = any(MemberAccess ma | - ma.getQualifier().getType() instanceof TupleType and - exprFrom = ma.getQualifier() - ) - } - - /** Gets the qualifier of element access `ea`. */ - private Expr getElementAccessQualifier(ElementAccess ea) { - result = ea.getQualifier() - } - /** * A taint tracking configuration. * @@ -163,7 +82,7 @@ module TaintTracking { override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { isAdditionalTaintStep(pred, succ) or localAdditionalTaintStep(pred, succ) or - DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred.asExpr(), succ, false) + DataFlow::Internal::flowThroughCallableLibraryOutRef(_, pred, succ, false) } final @@ -191,7 +110,135 @@ module TaintTracking { } } - private predicate canYieldReturn(Callable c, Expr e) { - c.getSourceDeclaration().canYieldReturn(e) + /** INTERNAL: Do not use. */ + module Internal { + predicate canYieldReturn(Callable c, Expr e) { + c.getSourceDeclaration().canYieldReturn(e) + } + + private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) { + result = node.asParameter() or + result = node.asExpr() + } + + private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + asCilDataFlowNode(nodeFrom).getALocalFlowSucc(asCilDataFlowNode(nodeTo), any(CIL::Tainted t)) + } + + /** Gets the qualifier of element access `ea`. */ + private Expr getElementAccessQualifier(ElementAccess ea) { + result = ea.getQualifier() + } + + private class LocalTaintExprStepConfiguration extends DataFlow::Internal::ExprStepConfiguration { + LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" } + + override predicate stepsToExpr(Expr exprFrom, Expr exprTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + exactScope = false and + ( + // Taint propagation using library code + DataFlow::Internal::LocalFlow::libraryFlow(exprFrom, exprTo, scope, isSuccessor, false) + or + // Taint from assigned value to element qualifier (`x[i] = 0`) + exists(AssignExpr ae | + exprFrom = ae.getRValue() and + exprTo.(AssignableRead) = getElementAccessQualifier+(ae.getLValue()) and + scope = ae and + isSuccessor = false + ) + or + // Taint from array initializer + exprFrom = exprTo.(ArrayCreation).getInitializer().getAnElement() and + scope = exprTo and + isSuccessor = false + or + // Taint from object initializer + exists(ElementInitializer ei | + ei = exprTo.(ObjectCreation).getInitializer().(CollectionInitializer).getAnElementInitializer() and + exprFrom = ei.getArgument(ei.getNumberOfArguments() - 1) and // assume the last argument is the value (i.e., not a key) + scope = exprTo and + isSuccessor = false + ) + or + // Taint from element qualifier + exprFrom = exprTo.(ElementAccess).getQualifier() and + scope = exprTo and + isSuccessor = true + or + exprFrom = exprTo.(AddExpr).getAnOperand() and + scope = exprTo and + isSuccessor = true + or + // A comparison expression where taint can flow from one of the + // operands if the other operand is a constant value. + exists(ComparisonTest ct, Expr other | + ct.getExpr() = exprTo and + exprFrom = ct.getAnArgument() and + other = ct.getAnArgument() and + other.stripCasts().hasValue() and + exprFrom != other and + scope = exprTo and + isSuccessor = true + ) + or + exprFrom = exprTo.(LogicalOperation).getAnOperand() and + scope = exprTo and + isSuccessor = false + or + // Taint from tuple argument + exprTo = any(TupleExpr te | + exprFrom = te.getAnArgument() and + te.isReadAccess() and + scope = exprTo and + isSuccessor = true + ) + or + exprFrom = exprTo.(InterpolatedStringExpr).getAChild() and + scope = exprTo and + isSuccessor = true + or + // Taint from tuple expression + exprTo = any(MemberAccess ma | + ma.getQualifier().getType() instanceof TupleType and + exprFrom = ma.getQualifier() and + scope = exprTo and + isSuccessor = true + ) + ) + } + + override predicate stepsToDefinition(Expr exprFrom, AssignableDefinition defTo, ControlFlowElement scope, boolean exactScope, boolean isSuccessor) { + // Taint from `foreach` expression + exists(ForeachStmt fs | + exprFrom = fs.getIterableExpr() and + defTo.(AssignableDefinitions::LocalVariableDefinition).getDeclaration() = fs.getVariableDeclExpr() and + isSuccessor = true + | + scope = fs and + exactScope = true + or + scope = fs.getIterableExpr() and + exactScope = false + or + scope = fs.getVariableDeclExpr() and + exactScope = false + ) + } + } + + cached module Cached { + cached predicate forceCachingInSameStage() { any() } + + cached predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + DataFlow::Internal::Cached::forceCachingInSameStage() and + any(LocalTaintExprStepConfiguration x).hasStep(nodeFrom, nodeTo) + or + DataFlow::Internal::flowOutOfDelegateLibraryCall(nodeFrom, nodeTo, false) + or + localTaintStepCil(nodeFrom, nodeTo) + } + } + import Cached } + private import Internal } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll index f87f212c70e..a5fd7f00b45 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Call.qll @@ -517,7 +517,7 @@ class DelegateCall extends Call, @delegate_invocation_expr { ) or exists(AddEventSource aes, CallContext::CallContext cc2 | - aes = this.getAnAddEventSource() and + aes = this.getAnAddEventSource(_) and result = aes.getARuntimeTarget(cc2) | aes = this.getAnAddEventSourceSameEnclosingCallable() and @@ -529,18 +529,17 @@ class DelegateCall extends Call, @delegate_invocation_expr { ) } - private AddEventSource getAnAddEventSource() { - this.getDelegateExpr().(EventAccess).getTarget() = result.getEvent() + private AddEventSource getAnAddEventSource(Callable enclosingCallable) { + this.getDelegateExpr().(EventAccess).getTarget() = result.getEvent() and + enclosingCallable = result.getExpr().getEnclosingCallable() } private AddEventSource getAnAddEventSourceSameEnclosingCallable() { - result = getAnAddEventSource() and - result.getExpr().getEnclosingCallable() = this.getEnclosingCallable() + result = getAnAddEventSource(this.getEnclosingCallable()) } private AddEventSource getAnAddEventSourceDifferentEnclosingCallable() { - result = getAnAddEventSource() and - result.getExpr().getEnclosingCallable() != this.getEnclosingCallable() + exists(Callable c | result = getAnAddEventSource(c) | c != this.getEnclosingCallable()) } override Callable getARuntimeTarget() { result = getARuntimeTarget(_) } diff --git a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll index 22e600513ed..25a4bf5761f 100644 --- a/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll +++ b/csharp/ql/src/semmle/code/csharp/exprs/Expr.qll @@ -670,7 +670,10 @@ class TupleExpr extends Expr, @tuple_expr { Expr getAnArgument() { result = getArgument(_) } /** Holds if this tuple is a read access. */ - predicate isReadAccess() { not exists(AssignExpr e | this = e.getLValue().getAChildExpr*()) } + predicate isReadAccess() { + not exists(AssignExpr e | this = e.getLValue().getAChildExpr*()) and + not exists(ForeachStmt fs | this = fs.getVariableDeclTuple().getAChildExpr*()) + } } /** diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll index bb1832c39ac..b99e5215592 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/TaintedPath.qll @@ -123,9 +123,9 @@ module TaintedPath { */ class PathCheck extends Sanitizer { PathCheck() { - // This expression is structurally replicated in a dominating guard which is not a "weak" check. - exists(Expr e | - this.getExpr().(GuardedExpr).isGuardedBy(_, e, _) and + // This expression is structurally replicated in a dominating guard which is not a "weak" check + exists(Expr e, AbstractValues::BooleanValue v | + exists(this.(GuardedDataFlowNode).getAGuard(e, v)) and not inWeakCheck(e) ) } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll index a809ff7bc6c..dc34267ffaf 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/UrlRedirect.qll @@ -98,8 +98,9 @@ module UrlRedirect { */ class IsLocalUrlSanitizer extends Sanitizer { IsLocalUrlSanitizer() { - exists(MethodCall mc | mc.getTarget().hasName("IsLocalUrl") | - this.getExpr().(GuardedExpr).isGuardedBy(mc, mc.getArgument(0), true) + exists(MethodCall mc, AbstractValues::BooleanValue v | mc.getTarget().hasName("IsLocalUrl") | + mc = this.(GuardedDataFlowNode).getAGuard(mc.getArgument(0), v) and + v.getValue() = true ) } } diff --git a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll index e5787a313f9..d5b9f24d0b1 100644 --- a/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll +++ b/csharp/ql/src/semmle/code/csharp/security/dataflow/ZipSlip.qll @@ -127,10 +127,10 @@ module ZipSlip { */ class StringCheckSanitizer extends Sanitizer { StringCheckSanitizer() { - exists(GuardedExpr ge, MethodCall mc, Expr startsWithQualifier | - ge = this.asExpr() and - ge.isGuardedBy(mc, startsWithQualifier, true) + exists(MethodCall mc, Expr startsWithQualifier, AbstractValues::BooleanValue v | + mc = this.(GuardedDataFlowNode).getAGuard(startsWithQualifier, v) | + v.getValue() = true and mc.getTarget().hasQualifiedName("System.String", "StartsWith") and mc.getQualifier() = startsWithQualifier and // A StartsWith check against Path.Combine is not sufficient, because the ".." elements have diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected index 17d861787dc..ee01db7f6ed 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlock.expected @@ -243,6 +243,8 @@ | Foreach.cs:36:10:36:11 | exit M6 | Foreach.cs:36:10:36:11 | exit M6 | 1 | | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | 1 | | Foreach.cs:38:26:38:26 | String x | Foreach.cs:39:11:39:11 | ; | 4 | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:17 | ... + ... | 3 | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:31 | ... + ... | 3 | | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | exit Initializers | 3 | | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | exit M | 23 | | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:23:3:23 | access to parameter i | 3 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected b/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected index bc617e1527e..da29acbeb4b 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/BasicBlockDominance.expected @@ -504,6 +504,8 @@ | post | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | post | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | post | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | +| post | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | +| post | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | | post | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | post | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | enter M | | post | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | @@ -1910,6 +1912,8 @@ | pre | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | | pre | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | Foreach.cs:38:26:38:26 | String x | | pre | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:26:38:26 | String x | +| pre | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | +| pre | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | | pre | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:5:6:16 | enter Initializers | | pre | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:8:10:8:10 | enter M | | pre | NullCoalescing.cs:3:9:3:10 | enter M1 | NullCoalescing.cs:3:9:3:10 | enter M1 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected index 71f86f41d72..ab282094823 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/Dominance.expected @@ -896,6 +896,10 @@ | post | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:26:38:26 | String x | | post | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:37:5:40:5 | {...} | | post | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:18:38:34 | (..., ...) | +| post | Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:17:3:17 | 1 | +| post | Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:13 | access to field H | +| post | Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:31:4:31 | 2 | +| post | Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:27 | access to field H | | post | Initializers.cs:6:5:6:16 | exit Initializers | Initializers.cs:6:28:6:30 | {...} | | post | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:5:6:16 | enter Initializers | | post | Initializers.cs:8:10:8:10 | exit M | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | @@ -909,9 +913,9 @@ | post | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:17:10:53 | object creation of type Initializers | | post | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:44:10:44 | 0 | | post | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:40 | access to field F | -| post | Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:40:10:44 | ... = ... | +| post | Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:40:10:44 | ... = ... | | post | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:51:10:51 | 1 | -| post | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:47 | access to field G | +| post | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:47 | access to property G | | post | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:10:13:10:53 | Initializers i = ... | | post | Initializers.cs:11:13:11:14 | access to local variable iz | Initializers.cs:11:9:11:64 | ... ...; | | post | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | Initializers.cs:11:37:11:63 | { ..., ... } | @@ -3141,6 +3145,10 @@ | pre | Foreach.cs:38:26:38:26 | String x | Foreach.cs:38:33:38:33 | Int32 y | | pre | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | | pre | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | +| pre | Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | +| pre | Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | +| pre | Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | +| pre | Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | | pre | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:28:6:30 | {...} | | pre | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | | pre | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:9:5:12:5 | {...} | @@ -3152,9 +3160,9 @@ | pre | Initializers.cs:10:34:10:35 | "" | Initializers.cs:10:17:10:53 | object creation of type Initializers | | pre | Initializers.cs:10:38:10:53 | { ..., ... } | Initializers.cs:10:13:10:53 | Initializers i = ... | | pre | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:44:10:44 | 0 | -| pre | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | +| pre | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | | pre | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:44 | ... = ... | -| pre | Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:51:10:51 | 1 | +| pre | Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:51:10:51 | 1 | | pre | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:38:10:53 | { ..., ... } | | pre | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:51 | ... = ... | | pre | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:14 | access to local variable iz | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected index 39fc3e21505..2574f01b6f8 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ElementGraph.expected @@ -685,6 +685,10 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | | Initializers.cs:9:5:12:5 | {...} | Initializers.cs:10:9:10:54 | ... ...; | semmle.label | successor | | Initializers.cs:10:9:10:54 | ... ...; | Initializers.cs:10:13:10:13 | access to local variable i | semmle.label | successor | | Initializers.cs:10:13:10:13 | access to local variable i | Initializers.cs:10:34:10:35 | "" | semmle.label | successor | @@ -693,9 +697,9 @@ | Initializers.cs:10:34:10:35 | "" | Initializers.cs:10:17:10:53 | object creation of type Initializers | semmle.label | successor | | Initializers.cs:10:38:10:53 | { ..., ... } | Initializers.cs:10:13:10:53 | Initializers i = ... | semmle.label | successor | | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:44:10:44 | 0 | semmle.label | successor | -| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | semmle.label | successor | +| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | semmle.label | successor | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:44 | ... = ... | semmle.label | successor | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:38:10:53 | { ..., ... } | semmle.label | successor | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:51 | ... = ... | semmle.label | successor | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:14 | access to local variable iz | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected index 9604f48630b..fd9627fbe19 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/EntryElement.expected @@ -727,6 +727,12 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | +| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:13 | access to field H | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | +| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:27 | access to field H | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:28:6:30 | {...} | | Initializers.cs:9:5:12:5 | {...} | Initializers.cs:9:5:12:5 | {...} | | Initializers.cs:10:9:10:54 | ... ...; | Initializers.cs:10:9:10:54 | ... ...; | @@ -738,8 +744,8 @@ | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:40:10:40 | access to field F | | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:40:10:40 | access to field F | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:44:10:44 | 0 | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:47:10:47 | access to field G | -| Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:47:10:47 | access to property G | +| Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:51:10:51 | 1 | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:9:11:64 | ... ...; | | Initializers.cs:11:13:11:14 | access to local variable iz | Initializers.cs:11:13:11:14 | access to local variable iz | @@ -750,6 +756,7 @@ | Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:39:11:39 | access to local variable i | | Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:59:11:60 | "" | | Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:59:11:60 | "" | +| Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:20:14:20 | 1 | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | | NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:28 | ... ?? ... | | NullCoalescing.cs:3:28:3:28 | 0 | NullCoalescing.cs:3:28:3:28 | 0 | diff --git a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected index b8dad69c8ee..38026741078 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/ExitElement.expected @@ -969,6 +969,12 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:33:38:33 | Int32 y | normal | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:39:38:42 | access to parameter args | normal | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:39:11:39:11 | ; | normal | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:13:3:13 | access to field H | normal | +| Initializers.cs:3:13:3:17 | ... + ... | Initializers.cs:3:13:3:17 | ... + ... | normal | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:17:3:17 | 1 | normal | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:27:4:27 | access to field H | normal | +| Initializers.cs:4:27:4:31 | ... + ... | Initializers.cs:4:27:4:31 | ... + ... | normal | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:31:4:31 | 2 | normal | | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:28:6:30 | {...} | normal | | Initializers.cs:9:5:12:5 | {...} | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | normal | | Initializers.cs:10:9:10:54 | ... ...; | Initializers.cs:10:13:10:53 | Initializers i = ... | normal | @@ -980,7 +986,7 @@ | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:40:10:40 | access to field F | normal | | Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:40:10:44 | ... = ... | normal | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:44:10:44 | 0 | normal | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:47:10:47 | access to field G | normal | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:47:10:47 | access to property G | normal | | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:47:10:51 | ... = ... | normal | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:51:10:51 | 1 | normal | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:63 | Initializers[] iz = ... | normal | @@ -992,6 +998,7 @@ | Initializers.cs:11:39:11:39 | access to local variable i | Initializers.cs:11:39:11:39 | access to local variable i | normal | | Initializers.cs:11:42:11:61 | object creation of type Initializers | Initializers.cs:11:42:11:61 | object creation of type Initializers | normal | | Initializers.cs:11:59:11:60 | "" | Initializers.cs:11:59:11:60 | "" | normal | +| Initializers.cs:14:20:14:20 | 1 | Initializers.cs:14:20:14:20 | 1 | normal | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null | | NullCoalescing.cs:3:23:3:23 | access to parameter i | NullCoalescing.cs:3:23:3:23 | access to parameter i | null | | NullCoalescing.cs:3:23:3:28 | ... ?? ... | NullCoalescing.cs:3:23:3:23 | access to parameter i | non-null | diff --git a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs index 2c4a2f6e7ed..df1fe8422dd 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs +++ b/csharp/ql/test/library-tests/controlflow/graph/Initializers.cs @@ -1,7 +1,7 @@ class Initializers { - int F; - int G; + int F = H + 1; + int G { get; set; } = H + 2; Initializers(string s) { } @@ -10,4 +10,6 @@ class Initializers var i = new Initializers("") { F = 0, G = 1 }; var iz = new Initializers[] { i, new Initializers("") }; } + + static int H = 1; } diff --git a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected index f6f0a429797..01d5a0df970 100644 --- a/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected +++ b/csharp/ql/test/library-tests/controlflow/graph/NodeGraph.expected @@ -1034,6 +1034,10 @@ | Foreach.cs:38:33:38:33 | Int32 y | Foreach.cs:38:18:38:34 | (..., ...) | semmle.label | successor | | Foreach.cs:38:39:38:42 | access to parameter args | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | | Foreach.cs:39:11:39:11 | ; | Foreach.cs:38:9:39:11 | foreach (... ... in ...) ... | semmle.label | successor | +| Initializers.cs:3:13:3:13 | access to field H | Initializers.cs:3:17:3:17 | 1 | semmle.label | successor | +| Initializers.cs:3:17:3:17 | 1 | Initializers.cs:3:13:3:17 | ... + ... | semmle.label | successor | +| Initializers.cs:4:27:4:27 | access to field H | Initializers.cs:4:31:4:31 | 2 | semmle.label | successor | +| Initializers.cs:4:31:4:31 | 2 | Initializers.cs:4:27:4:31 | ... + ... | semmle.label | successor | | Initializers.cs:6:5:6:16 | enter Initializers | Initializers.cs:6:28:6:30 | {...} | semmle.label | successor | | Initializers.cs:6:28:6:30 | {...} | Initializers.cs:6:5:6:16 | exit Initializers | semmle.label | successor | | Initializers.cs:8:10:8:10 | enter M | Initializers.cs:9:5:12:5 | {...} | semmle.label | successor | @@ -1045,9 +1049,9 @@ | Initializers.cs:10:34:10:35 | "" | Initializers.cs:10:17:10:53 | object creation of type Initializers | semmle.label | successor | | Initializers.cs:10:38:10:53 | { ..., ... } | Initializers.cs:10:13:10:53 | Initializers i = ... | semmle.label | successor | | Initializers.cs:10:40:10:40 | access to field F | Initializers.cs:10:44:10:44 | 0 | semmle.label | successor | -| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to field G | semmle.label | successor | +| Initializers.cs:10:40:10:44 | ... = ... | Initializers.cs:10:47:10:47 | access to property G | semmle.label | successor | | Initializers.cs:10:44:10:44 | 0 | Initializers.cs:10:40:10:44 | ... = ... | semmle.label | successor | -| Initializers.cs:10:47:10:47 | access to field G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | +| Initializers.cs:10:47:10:47 | access to property G | Initializers.cs:10:51:10:51 | 1 | semmle.label | successor | | Initializers.cs:10:47:10:51 | ... = ... | Initializers.cs:10:38:10:53 | { ..., ... } | semmle.label | successor | | Initializers.cs:10:51:10:51 | 1 | Initializers.cs:10:47:10:51 | ... = ... | semmle.label | successor | | Initializers.cs:11:9:11:64 | ... ...; | Initializers.cs:11:13:11:14 | access to local variable iz | semmle.label | successor | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected new file mode 100644 index 00000000000..506555c31d5 --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.expected @@ -0,0 +1,232 @@ +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | Assert.cs:10:22:10:22 | access to local variable s | non-null | +| Assert.cs:11:27:11:27 | access to local variable s | Assert.cs:10:22:10:30 | ... != ... | Assert.cs:10:22:10:22 | access to local variable s | true | +| Assert.cs:18:27:18:27 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | Assert.cs:17:23:17:23 | access to local variable s | null | +| Assert.cs:25:27:25:27 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | Assert.cs:24:26:24:26 | access to local variable s | non-null | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | Assert.cs:31:23:31:23 | access to local variable s | null | +| Assert.cs:32:27:32:27 | access to local variable s | Assert.cs:31:23:31:31 | ... == ... | Assert.cs:31:23:31:23 | access to local variable s | true | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | Assert.cs:38:23:38:23 | access to local variable s | non-null | +| Assert.cs:39:27:39:27 | access to local variable s | Assert.cs:38:23:38:31 | ... != ... | Assert.cs:38:23:38:23 | access to local variable s | true | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | Assert.cs:45:24:45:24 | access to local variable s | null | +| Assert.cs:46:27:46:27 | access to local variable s | Assert.cs:45:24:45:32 | ... != ... | Assert.cs:45:24:45:24 | access to local variable s | false | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | Assert.cs:52:24:52:24 | access to local variable s | non-null | +| Assert.cs:53:27:53:27 | access to local variable s | Assert.cs:52:24:52:32 | ... == ... | Assert.cs:52:24:52:24 | access to local variable s | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | Assert.cs:58:20:58:20 | access to parameter b | false | +| Assert.cs:59:36:59:36 | access to parameter b | Assert.cs:58:20:58:32 | ... ? ... : ... | Assert.cs:58:20:58:20 | access to parameter b | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | Assert.cs:59:23:59:23 | access to local variable s | non-null | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:31 | ... != ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:60:27:60:27 | access to local variable s | Assert.cs:59:23:59:36 | ... && ... | Assert.cs:59:23:59:23 | access to local variable s | true | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | Assert.cs:65:20:65:20 | access to parameter b | false | +| Assert.cs:66:37:66:37 | access to parameter b | Assert.cs:65:20:65:32 | ... ? ... : ... | Assert.cs:65:20:65:20 | access to parameter b | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | Assert.cs:66:24:66:24 | access to local variable s | non-null | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:32 | ... == ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:67:27:67:27 | access to local variable s | Assert.cs:66:24:66:37 | ... \|\| ... | Assert.cs:66:24:66:24 | access to local variable s | false | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | Assert.cs:72:20:72:20 | access to parameter b | true | +| Assert.cs:73:36:73:36 | access to parameter b | Assert.cs:72:20:72:32 | ... ? ... : ... | Assert.cs:72:20:72:20 | access to parameter b | null | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | Assert.cs:73:23:73:23 | access to local variable s | null | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:31 | ... == ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:74:27:74:27 | access to local variable s | Assert.cs:73:23:73:36 | ... && ... | Assert.cs:73:23:73:23 | access to local variable s | true | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | Assert.cs:79:20:79:20 | access to parameter b | true | +| Assert.cs:80:37:80:37 | access to parameter b | Assert.cs:79:20:79:32 | ... ? ... : ... | Assert.cs:79:20:79:20 | access to parameter b | null | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | Assert.cs:80:24:80:24 | access to local variable s | null | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:32 | ... != ... | Assert.cs:80:24:80:24 | access to local variable s | false | +| Assert.cs:81:27:81:27 | access to local variable s | Assert.cs:80:24:80:37 | ... \|\| ... | Assert.cs:80:24:80:24 | access to local variable s | false | +| 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 | +| Guards.cs:14:31:14:31 | 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:12:13:12:24 | ... > ... | Guards.cs:12:13:12:13 | access to parameter s | true | +| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:13 | access to parameter s | Guards.cs:24:13:24:13 | access to parameter s | non-null | +| Guards.cs:26:31:26:31 | access to parameter s | Guards.cs:24:13:24:21 | ... != ... | Guards.cs:24:13:24:13 | access to parameter s | true | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:36 | !... | Guards.cs:32:35:32:35 | access to parameter x | true | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:35:32:35 | access to parameter x | true | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:14:32:36 | call to method IsNullOrEmpty | Guards.cs:32:35:32:35 | access to parameter x | false | +| Guards.cs:33:31:33:31 | access to parameter x | Guards.cs:32:35:32:35 | access to parameter x | Guards.cs:32:35:32:35 | access to parameter x | non-null | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:13:32:51 | ... & ... | Guards.cs:32:42:32:42 | access to parameter y | true | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:40:32:51 | !... | Guards.cs:32:42:32:42 | access to parameter y | true | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:42 | access to parameter y | Guards.cs:32:42:32:42 | access to parameter y | non-null | +| Guards.cs:33:35:33:35 | access to parameter y | Guards.cs:32:42:32:50 | ... == ... | Guards.cs:32:42:32:42 | access to parameter y | false | +| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:13 | access to parameter x | Guards.cs:35:13:35:13 | access to parameter x | non-null | +| Guards.cs:36:32:36:32 | access to parameter x | Guards.cs:35:13:35:21 | ... == ... | Guards.cs:35:13:35:13 | access to parameter x | false | +| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:26 | access to parameter y | Guards.cs:35:26:35:26 | access to parameter y | non-null | +| Guards.cs:36:36:36:36 | access to parameter y | Guards.cs:35:26:35:34 | ... == ... | Guards.cs:35:26:35:26 | access to parameter y | false | +| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:15 | access to parameter x | Guards.cs:38:15:38:15 | access to parameter x | non-null | +| Guards.cs:39:31:39:31 | access to parameter x | Guards.cs:38:15:38:23 | ... == ... | Guards.cs:38:15:38:15 | access to parameter x | false | +| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:28 | access to parameter y | Guards.cs:38:28:38:28 | access to parameter y | non-null | +| Guards.cs:39:35:39:35 | access to parameter y | Guards.cs:38:28:38:36 | ... == ... | Guards.cs:38:28:38:28 | access to parameter y | false | +| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:17 | access to parameter x | Guards.cs:41:17:41:17 | access to parameter x | non-null | +| Guards.cs:42:32:42:32 | access to parameter x | Guards.cs:41:17:41:25 | ... != ... | Guards.cs:41:17:41:17 | access to parameter x | true | +| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:30 | access to parameter y | Guards.cs:41:30:41:30 | access to parameter y | non-null | +| Guards.cs:42:36:42:36 | access to parameter y | Guards.cs:41:30:41:38 | ... != ... | Guards.cs:41:30:41:30 | access to parameter y | true | +| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:17 | access to field Field | Guards.cs:47:13:47:17 | access to field Field | non-null | +| Guards.cs:48:31:48:40 | access to field Field | Guards.cs:47:13:47:25 | ... != ... | Guards.cs:47:13:47:17 | access to field Field | true | +| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:19 | access to field Field | Guards.cs:53:13:53:13 | access to parameter g | non-null | +| Guards.cs:55:27:55:27 | access to parameter g | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:13 | access to parameter g | false | +| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:19 | access to field Field | Guards.cs:53:13:53:19 | access to field Field | non-null | +| Guards.cs:55:27:55:33 | access to field Field | Guards.cs:53:13:53:27 | ... == ... | Guards.cs:53:13:53:19 | access to field Field | false | +| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:13 | access to parameter g | non-null | +| Guards.cs:62:27:62:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false | +| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:22 | access to property Property | non-null | +| Guards.cs:62:27:62:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false | +| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:31 | access to property Property | non-null | +| Guards.cs:62:27:62:45 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:31 | access to property Property | false | +| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:37 | access to field Field | non-null | +| Guards.cs:62:27:62:51 | access to field Field | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:37 | access to field Field | false | +| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:13 | access to parameter g | non-null | +| Guards.cs:63:27:63:27 | access to parameter g | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:13 | access to parameter g | false | +| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:37 | access to field Field | Guards.cs:60:13:60:22 | access to property Property | non-null | +| Guards.cs:63:27:63:36 | access to property Property | Guards.cs:60:13:60:45 | ... == ... | Guards.cs:60:13:60:22 | access to property Property | false | +| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:16 | access to parameter s | Guards.cs:68:16:68:16 | access to parameter s | non-null | +| Guards.cs:70:31:70:31 | access to parameter s | Guards.cs:68:16:68:24 | ... != ... | Guards.cs:68:16:68:16 | access to parameter s | true | +| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:13 | access to parameter s | Guards.cs:78:13:78:13 | access to parameter s | non-null | +| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:13:78:26 | ... == ... | Guards.cs:78:13:78:13 | access to parameter s | true | +| Guards.cs:79:31:79:31 | access to parameter s | Guards.cs:78:15:78:21 | access to property Length | Guards.cs:78:13:78:13 | access to parameter s | non-null | +| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:13 | access to parameter s | Guards.cs:80:13:80:13 | access to parameter s | non-null | +| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:13:80:25 | ... > ... | Guards.cs:80:13:80:13 | access to parameter s | true | +| Guards.cs:81:31:81:31 | access to parameter s | Guards.cs:80:15:80:21 | access to property Length | Guards.cs:80:13:80:13 | access to parameter s | non-null | +| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:13 | access to parameter s | Guards.cs:82:13:82:13 | access to parameter s | non-null | +| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:13:82:26 | ... >= ... | Guards.cs:82:13:82:13 | access to parameter s | true | +| Guards.cs:83:31:83:31 | access to parameter s | Guards.cs:82:15:82:21 | access to property Length | Guards.cs:82:13:82:13 | access to parameter s | non-null | +| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:13 | access to parameter s | Guards.cs:84:13:84:13 | access to parameter s | non-null | +| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:13:84:26 | ... < ... | Guards.cs:84:13:84:13 | access to parameter s | true | +| Guards.cs:85:31:85:31 | access to parameter s | Guards.cs:84:15:84:21 | access to property Length | Guards.cs:84:13:84:13 | access to parameter s | non-null | +| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:13 | access to parameter s | Guards.cs:86:13:86:13 | access to parameter s | non-null | +| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:13:86:27 | ... <= ... | Guards.cs:86:13:86:13 | access to parameter s | true | +| Guards.cs:87:31:87:31 | access to parameter s | Guards.cs:86:15:86:21 | access to property Length | Guards.cs:86:13:86:13 | access to parameter s | non-null | +| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | non-null | +| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | true | +| Guards.cs:89:31:89:31 | access to parameter s | Guards.cs:88:15:88:21 | access to property Length | Guards.cs:88:13:88:13 | access to parameter s | non-null | +| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | Guards.cs:88:13:88:13 | access to parameter s | null | +| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:13:88:29 | ... != ... | Guards.cs:88:13:88:13 | access to parameter s | false | +| Guards.cs:91:31:91:31 | access to parameter s | Guards.cs:88:15:88:21 | access to property Length | Guards.cs:88:13:88:13 | access to parameter s | null | +| Guards.cs:93:31:93:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | true | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:13 | access to parameter s | Guards.cs:92:13:92:13 | access to parameter s | non-null | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:25 | ... - ... | Guards.cs:92:13:92:13 | access to parameter s | non-null | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:13:92:30 | ... != ... | Guards.cs:92:13:92:13 | access to parameter s | false | +| Guards.cs:95:31:95:31 | access to parameter s | Guards.cs:92:15:92:21 | access to property Length | Guards.cs:92:13:92:13 | access to parameter s | non-null | +| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:13 | access to parameter s | Guards.cs:96:13:96:13 | access to parameter s | non-null | +| Guards.cs:97:31:97:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | true | +| Guards.cs:99:31:99:31 | access to parameter s | Guards.cs:96:13:96:19 | ... == ... | Guards.cs:96:13:96:13 | access to parameter s | false | +| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null | +| Guards.cs:106:9:106:9 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false | +| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null | +| Guards.cs:107:27:107:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false | +| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:37 | access to field Field | Guards.cs:104:13:104:13 | access to parameter g | non-null | +| Guards.cs:108:27:108:27 | access to parameter g | Guards.cs:104:13:104:45 | ... == ... | Guards.cs:104:13:104:13 | access to parameter g | false | +| Guards.cs:114:14:114:14 | access to parameter g | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:21 | access to parameter g | null | +| Guards.cs:114:14:114:23 | access to property Property | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:30 | access to property Property | null | +| Guards.cs:114:14:114:32 | access to property Property | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:39 | access to property Property | null | +| Guards.cs:114:14:114:38 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | Guards.cs:113:21:113:45 | access to field Field | null | +| Guards.cs:116:27:116:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:116:27:116:36 | access to property Property | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:26 | access to property Property | non-null | +| Guards.cs:116:27:116:45 | access to property Property | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:35 | access to property Property | non-null | +| Guards.cs:116:27:116:51 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:41 | access to field Field | non-null | +| Guards.cs:117:9:117:9 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:118:27:118:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:119:27:119:27 | access to parameter g | Guards.cs:115:17:115:41 | access to field Field | Guards.cs:115:17:115:17 | access to parameter g | non-null | +| Guards.cs:125:29:125:30 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | Guards.cs:125:18:125:19 | access to parameter s1 | non-null | +| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | null | +| Guards.cs:131:20:131:20 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | true | +| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | Guards.cs:130:13:130:13 | access to parameter s | non-null | +| Guards.cs:132:16:132:16 | access to parameter s | Guards.cs:130:13:130:21 | ... is ... | Guards.cs:130:13:130:13 | access to parameter s | false | +| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | non-null | +| Guards.cs:138:20:138:20 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | true | +| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | Guards.cs:137:13:137:13 | access to parameter s | null | +| Guards.cs:139:16:139:16 | access to parameter s | Guards.cs:137:13:137:23 | ... is ... | Guards.cs:137:13:137:13 | access to parameter s | false | +| Guards.cs:146:16:146:16 | access to parameter o | Guards.cs:144:13:144:25 | ... is ... | Guards.cs:144:13:144:13 | access to parameter o | false | +| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case Action: | +| Guards.cs:154:24:154:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case ...: | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | +| Guards.cs:158:24:158:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | match case ...: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | +| Guards.cs:160:24:160:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | null | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case ...: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-match case Action a: | +| Guards.cs:162:24:162:24 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | Guards.cs:151:17:151:17 | access to parameter o | non-null | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:14:168:41 | call to method IsNullOrWhiteSpace | Guards.cs:168:40:168:40 | access to parameter x | false | +| Guards.cs:169:31:169:31 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | Guards.cs:168:40:168:40 | access to parameter x | non-null | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:14:189:25 | call to method NullTest1 | Guards.cs:189:24:189:24 | access to parameter s | false | +| Guards.cs:190:31:190:31 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | Guards.cs:189:24:189:24 | access to parameter s | non-null | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:14:191:25 | call to method NullTest2 | Guards.cs:191:24:191:24 | access to parameter s | false | +| Guards.cs:192:31:192:31 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | Guards.cs:191:24:191:24 | access to parameter s | non-null | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:14:193:25 | call to method NullTest3 | Guards.cs:193:24:193:24 | access to parameter s | false | +| Guards.cs:194:31:194:31 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | Guards.cs:193:24:193:24 | access to parameter s | non-null | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:13:195:27 | call to method NotNullTest4 | Guards.cs:195:26:195:26 | access to parameter s | true | +| Guards.cs:196:31:196:31 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | Guards.cs:195:26:195:26 | access to parameter s | non-null | +| Guards.cs:198:31:198:31 | access to parameter s | Guards.cs:197:14:197:29 | call to method NullTestWrong | Guards.cs:197:28:197:28 | access to parameter s | false | +| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | non-null | +| Guards.cs:205:13:205:13 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true | +| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | Guards.cs:203:13:203:13 | access to parameter o | non-null | +| Guards.cs:208:17:208:17 | access to parameter o | Guards.cs:203:13:203:21 | ... != ... | Guards.cs:203:13:203:13 | access to parameter o | true | +| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | Splitting.cs:12:17:12:17 | access to parameter o | non-null | +| Splitting.cs:13:17:13:17 | [b (line 9): true] access to parameter o | Splitting.cs:12:17:12:25 | ... != ... | Splitting.cs:12:17:12:17 | access to parameter o | true | +| Splitting.cs:14:13:14:13 | [b (line 9): false] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | false | +| Splitting.cs:14:13:14:13 | [b (line 9): true] access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | Splitting.cs:11:13:11:13 | access to parameter b | true | +| Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | non-null | +| Splitting.cs:23:24:23:24 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | true | +| Splitting.cs:24:13:24:13 | [b (line 19): false] access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | false | +| Splitting.cs:24:13:24:13 | [b (line 19): true] access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | Splitting.cs:21:13:21:13 | access to parameter b | true | +| Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | Splitting.cs:22:17:22:17 | access to parameter o | null | +| Splitting.cs:25:13:25:13 | access to parameter o | Splitting.cs:22:17:22:25 | ... != ... | Splitting.cs:22:17:22:17 | access to parameter o | false | +| Splitting.cs:34:13:34:13 | [b (line 29): false] access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | false | +| Splitting.cs:34:13:34:13 | [b (line 29): true] access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | Splitting.cs:31:13:31:13 | access to parameter b | true | +| Splitting.cs:35:13:35:13 | access to parameter o | Splitting.cs:32:17:32:17 | access to parameter o | Splitting.cs:32:17:32:17 | access to parameter o | non-null | +| Splitting.cs:35:13:35:13 | access to parameter o | Splitting.cs:32:17:32:25 | ... == ... | Splitting.cs:32:17:32:17 | access to parameter o | false | +| Splitting.cs:44:17:44:17 | [b (line 39): true] access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | non-null | +| Splitting.cs:44:17:44:17 | [b (line 39): true] access to parameter o | Splitting.cs:41:13:41:21 | ... != ... | Splitting.cs:41:13:41:13 | access to parameter o | true | +| Splitting.cs:45:17:45:17 | [b (line 39): false] access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | false | +| Splitting.cs:45:17:45:17 | [b (line 39): true] access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | Splitting.cs:43:17:43:17 | access to parameter b | true | +| Splitting.cs:46:17:46:17 | access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | Splitting.cs:41:13:41:13 | access to parameter o | non-null | +| Splitting.cs:46:17:46:17 | access to parameter o | Splitting.cs:41:13:41:21 | ... != ... | Splitting.cs:41:13:41:13 | access to parameter o | true | +| Splitting.cs:55:13:55:13 | [b (line 50): false] access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | non-null | +| Splitting.cs:55:13:55:13 | [b (line 50): false] access to parameter o | Splitting.cs:54:13:54:21 | ... != ... | Splitting.cs:54:13:54:13 | access to parameter o | true | +| Splitting.cs:55:13:55:13 | [b (line 50): true] access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | Splitting.cs:54:13:54:13 | access to parameter o | non-null | +| Splitting.cs:55:13:55:13 | [b (line 50): true] access to parameter o | Splitting.cs:54:13:54:21 | ... != ... | Splitting.cs:54:13:54:13 | access to parameter o | true | +| Splitting.cs:56:13:56:13 | [b (line 50): false] access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | false | +| Splitting.cs:56:13:56:13 | [b (line 50): true] access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | Splitting.cs:52:13:52:13 | access to parameter b | true | +| Splitting.cs:66:20:66:20 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | non-null | +| Splitting.cs:66:20:66:20 | access to parameter o | Splitting.cs:65:13:65:21 | ... != ... | Splitting.cs:65:13:65:13 | access to parameter o | true | +| Splitting.cs:67:13:67:13 | [b (line 61): false] access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | false | +| Splitting.cs:67:13:67:13 | [b (line 61): true] access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | Splitting.cs:63:13:63:13 | access to parameter b | true | +| Splitting.cs:68:13:68:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | null | +| Splitting.cs:68:13:68:13 | access to parameter o | Splitting.cs:65:13:65:21 | ... != ... | Splitting.cs:65:13:65:13 | access to parameter o | false | +| Splitting.cs:69:16:69:16 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | Splitting.cs:65:13:65:13 | access to parameter o | null | +| Splitting.cs:69:16:69:16 | access to parameter o | Splitting.cs:65:13:65:21 | ... != ... | Splitting.cs:65:13:65:13 | access to parameter o | false | +| Splitting.cs:78:24:78:24 | access to parameter o | Splitting.cs:76:13:76:13 | access to parameter o | Splitting.cs:76:13:76:13 | access to parameter o | non-null | +| Splitting.cs:78:24:78:24 | access to parameter o | Splitting.cs:76:13:76:21 | ... != ... | Splitting.cs:76:13:76:13 | access to parameter o | true | +| Splitting.cs:79:13:79:13 | [b (line 72): false] access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | false | +| Splitting.cs:79:13:79:13 | [b (line 72): true] access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | Splitting.cs:74:13:74:13 | access to parameter b | true | +| Splitting.cs:88:9:88:9 | [b (line 84): true] access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | non-null | +| Splitting.cs:88:9:88:9 | [b (line 84): true] access to parameter o | Splitting.cs:87:26:87:34 | ... != ... | Splitting.cs:87:26:87:26 | access to parameter o | true | +| Splitting.cs:89:13:89:13 | [b (line 84): false] access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | false | +| Splitting.cs:89:13:89:13 | [b (line 84): true] access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | Splitting.cs:86:13:86:13 | access to parameter b | true | +| Splitting.cs:90:13:90:13 | access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | Splitting.cs:87:26:87:26 | access to parameter o | non-null | +| Splitting.cs:90:13:90:13 | access to parameter o | Splitting.cs:87:26:87:34 | ... != ... | Splitting.cs:87:26:87:26 | access to parameter o | true | +| Splitting.cs:98:13:98:13 | [b (line 94): false] access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | false | +| Splitting.cs:98:13:98:13 | [b (line 94): true] access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | Splitting.cs:96:13:96:13 | access to parameter b | true | +| Splitting.cs:99:13:99:13 | access to parameter o | Splitting.cs:97:26:97:26 | access to parameter o | Splitting.cs:97:26:97:26 | access to parameter o | null | +| Splitting.cs:99:13:99:13 | access to parameter o | Splitting.cs:97:26:97:34 | ... == ... | Splitting.cs:97:26:97:26 | access to parameter o | true | +| Splitting.cs:107:13:107:13 | [b (line 103): true] access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | non-null | +| Splitting.cs:107:13:107:13 | [b (line 103): true] access to parameter o | Splitting.cs:105:22:105:30 | ... != ... | Splitting.cs:105:22:105:22 | access to parameter o | true | +| Splitting.cs:108:13:108:13 | [b (line 103): false] access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | false | +| Splitting.cs:108:13:108:13 | [b (line 103): true] access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | Splitting.cs:106:13:106:13 | access to parameter b | true | +| Splitting.cs:109:13:109:13 | access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | Splitting.cs:105:22:105:22 | access to parameter o | non-null | +| Splitting.cs:109:13:109:13 | access to parameter o | Splitting.cs:105:22:105:30 | ... != ... | Splitting.cs:105:22:105:22 | access to parameter o | true | +| Splitting.cs:117:9:117:9 | [b (line 112): false] access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:117:9:117:9 | [b (line 112): false] access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:117:9:117:9 | [b (line 112): true] access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:117:9:117:9 | [b (line 112): true] access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:118:13:118:13 | [b (line 112): false] access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | false | +| Splitting.cs:118:13:118:13 | [b (line 112): true] access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | Splitting.cs:114:13:114:13 | access to parameter b | true | +| Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:119:13:119:13 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | Splitting.cs:116:22:116:22 | access to parameter o | non-null | +| Splitting.cs:120:16:120:16 | access to parameter o | Splitting.cs:116:22:116:30 | ... != ... | Splitting.cs:116:22:116:22 | access to parameter o | true | +| Splitting.cs:130:21:130:21 | [b (line 123): false] access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | +| Splitting.cs:132:25:132:25 | [b (line 123): false] access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | Splitting.cs:130:21:130:21 | access to parameter b | false | diff --git a/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql new file mode 100644 index 00000000000..82d843a2a41 --- /dev/null +++ b/csharp/ql/test/library-tests/controlflow/guards/GuardedControlFlowNode.ql @@ -0,0 +1,5 @@ +import csharp +import semmle.code.csharp.controlflow.Guards + +from GuardedControlFlowNode gcfn, Expr sub, AbstractValue v +select gcfn, gcfn.getAGuard(sub, v), sub, v diff --git a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected index 32766ee67a3..753fcec4869 100644 --- a/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected +++ b/csharp/ql/test/library-tests/csharp7/LocalTaintFlow.expected @@ -185,14 +185,8 @@ | CSharp7.cs:284:41:284:48 | access to property Key | CSharp7.cs:284:40:284:61 | (..., ...) | | CSharp7.cs:284:51:284:54 | access to parameter item | CSharp7.cs:284:51:284:60 | access to property Value | | CSharp7.cs:284:51:284:60 | access to property Value | CSharp7.cs:284:40:284:61 | (..., ...) | -| CSharp7.cs:286:23:286:23 | Int32 a | CSharp7.cs:286:18:286:34 | (..., ...) | -| CSharp7.cs:286:33:286:33 | String b | CSharp7.cs:286:18:286:34 | (..., ...) | | CSharp7.cs:286:39:286:42 | access to local variable list | CSharp7.cs:288:36:288:39 | access to local variable list | -| CSharp7.cs:288:23:288:23 | Int32 a | CSharp7.cs:288:18:288:31 | (..., ...) | -| CSharp7.cs:288:30:288:30 | String b | CSharp7.cs:288:18:288:31 | (..., ...) | | CSharp7.cs:288:36:288:39 | access to local variable list | CSharp7.cs:290:32:290:35 | access to local variable list | -| CSharp7.cs:290:23:290:23 | Int32 a | CSharp7.cs:290:18:290:27 | (..., ...) | -| CSharp7.cs:290:26:290:26 | String b | CSharp7.cs:290:18:290:27 | (..., ...) | | CSharp7.cs:298:17:298:19 | SSA def(x) | CSharp7.cs:298:22:298:39 | SSA phi(x) | | CSharp7.cs:298:19:298:19 | 0 | CSharp7.cs:298:17:298:19 | SSA def(x) | | CSharp7.cs:298:22:298:22 | access to local variable x | CSharp7.cs:298:22:298:25 | ... < ... | diff --git a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected index c825aadfb74..437ee46820d 100644 --- a/csharp/ql/test/library-tests/csharp7/TupleAccess.expected +++ b/csharp/ql/test/library-tests/csharp7/TupleAccess.expected @@ -40,6 +40,6 @@ | CSharp7.cs:224:9:224:18 | (..., ...) | write | | CSharp7.cs:225:9:225:18 | (..., ...) | write | | CSharp7.cs:284:40:284:61 | (..., ...) | read | -| CSharp7.cs:286:18:286:34 | (..., ...) | read | -| CSharp7.cs:288:18:288:31 | (..., ...) | read | -| CSharp7.cs:290:18:290:27 | (..., ...) | read | +| CSharp7.cs:286:18:286:34 | (..., ...) | write | +| CSharp7.cs:288:18:288:31 | (..., ...) | write | +| CSharp7.cs:290:18:290:27 | (..., ...) | write | diff --git a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll index 92d128462dc..2690f558847 100644 --- a/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll +++ b/csharp/ql/test/library-tests/dataflow/callablereturnsarg/Common.qll @@ -9,8 +9,9 @@ class Configuration extends DataFlow::Configuration { override predicate isSink(DataFlow::Node sink) { any() } override predicate isBarrier(DataFlow::Node node) { - exists(EQExpr eq, Expr e | - node.asExpr().(GuardedExpr).isGuardedBy(eq, e, true) and + exists(EQExpr eq, Expr e, AbstractValues::BooleanValue v | + eq = node.(GuardedDataFlowNode).getAGuard(e, v) | + v.getValue() = true and eq.getAnOperand() = e and eq.getAnOperand() instanceof NullLiteral ) diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected index 57084e1b711..2f41d7030f5 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.expected @@ -1,37 +1,40 @@ -| access to field SinkField0 | -| access to local variable sink0 | -| access to local variable sink1 | -| access to local variable sink10 | -| access to local variable sink11 | -| access to local variable sink19 | -| access to local variable sink2 | -| access to local variable sink20 | -| access to local variable sink23 | -| access to local variable sink27 | -| access to local variable sink28 | -| access to local variable sink29 | -| access to local variable sink3 | -| access to local variable sink30 | -| access to local variable sink31 | -| access to local variable sink32 | -| access to local variable sink33 | -| access to local variable sink34 | -| access to local variable sink35 | -| access to local variable sink36 | -| access to local variable sink37 | -| access to local variable sink38 | -| access to local variable sink4 | -| access to local variable sink5 | -| access to local variable sink6 | -| access to local variable sink7 | -| access to local variable sink8 | -| access to local variable sink9 | -| access to parameter sinkParam0 | -| access to parameter sinkParam1 | -| access to parameter sinkParam2 | -| access to parameter sinkParam3 | -| access to parameter sinkParam4 | -| access to parameter sinkParam5 | -| access to parameter sinkParam6 | -| access to parameter sinkParam7 | -| access to property SinkProperty0 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql b/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql index efc827dd6e6..62cfb8e7dc2 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlow.ql @@ -1,8 +1,6 @@ import csharp import Common -from Config c, DataFlow::Node source, DataFlow::Node sink, string s -where - c.hasFlow(source, sink) and - s = sink.toString() -select s order by s +from Config c, DataFlow::Node source, DataFlow::Node sink +where c.hasFlow(source, sink) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected index d02b28059d6..e4a65d2dd2c 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.expected @@ -172,6 +172,18 @@ edges | GlobalDataFlow.cs:377:16:377:21 | access to local variable sink11 | GlobalDataFlow.cs:159:22:159:43 | call to method TaintedParam | | GlobalDataFlow.cs:399:9:399:11 | value | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:193:22:193:32 | access to property OutProperty | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | nodes | Capture.cs:7:20:7:26 | tainted | | Capture.cs:9:9:13:9 | SSA capture def(tainted) | @@ -302,42 +314,61 @@ nodes | GlobalDataFlow.cs:399:9:399:11 | value | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | +| Splitting.cs:3:28:3:34 | tainted | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | #select -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | -| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | -| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | -| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | -| Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | -| Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | -| Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | -| Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | -| Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | -| Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | -| Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | -| Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | -| Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | -| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | -| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | -| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | -| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | diff --git a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql index a995769f0ed..fd042e29be3 100644 --- a/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql +++ b/csharp/ql/test/library-tests/dataflow/global/DataFlowPath.ql @@ -10,4 +10,4 @@ from Config c, DataFlow::PathNode source, DataFlow::PathNode sink, string s where c.hasFlowPath(source, sink) and s = sink.toString() -select sink, s, source, sink order by s +select sink, source, sink, s order by s diff --git a/csharp/ql/test/library-tests/dataflow/global/Splitting.cs b/csharp/ql/test/library-tests/dataflow/global/Splitting.cs new file mode 100644 index 00000000000..f313dafc65b --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/global/Splitting.cs @@ -0,0 +1,17 @@ +class Splitting +{ + void M1(bool b, string tainted) + { + if (b) + if (tainted == null) + return; + var x = Return(tainted); + Check(x); + if (b) + Check(x); + } + + static void Check(T x) { } + + static T Return(T x) => x; +} diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected index 7fe5b2cb1de..1a9a69643c0 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.expected @@ -1,53 +1,56 @@ -| access to field SinkField0 | -| access to local variable sink0 | -| access to local variable sink1 | -| access to local variable sink10 | -| access to local variable sink11 | -| access to local variable sink12 | -| access to local variable sink13 | -| access to local variable sink14 | -| access to local variable sink15 | -| access to local variable sink16 | -| access to local variable sink17 | -| access to local variable sink18 | -| access to local variable sink19 | -| access to local variable sink2 | -| access to local variable sink20 | -| access to local variable sink21 | -| access to local variable sink22 | -| access to local variable sink23 | -| access to local variable sink24 | -| access to local variable sink25 | -| access to local variable sink26 | -| access to local variable sink27 | -| access to local variable sink28 | -| access to local variable sink29 | -| access to local variable sink3 | -| access to local variable sink30 | -| access to local variable sink31 | -| access to local variable sink32 | -| access to local variable sink33 | -| access to local variable sink34 | -| access to local variable sink35 | -| access to local variable sink36 | -| access to local variable sink37 | -| access to local variable sink38 | -| access to local variable sink4 | -| access to local variable sink5 | -| access to local variable sink6 | -| access to local variable sink7 | -| access to local variable sink8 | -| access to local variable sink9 | -| access to parameter sinkParam0 | -| access to parameter sinkParam1 | -| access to parameter sinkParam10 | -| access to parameter sinkParam11 | -| access to parameter sinkParam2 | -| access to parameter sinkParam3 | -| access to parameter sinkParam4 | -| access to parameter sinkParam5 | -| access to parameter sinkParam6 | -| access to parameter sinkParam7 | -| access to parameter sinkParam8 | -| access to parameter sinkParam9 | -| access to property SinkProperty0 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | +| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | +| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | +| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | +| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | +| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | +| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | +| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | +| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | +| GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | +| GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | +| GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | +| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql index d57eb8e1e87..1fc9bb63fc2 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTracking.ql @@ -11,8 +11,6 @@ class TTConfig extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { c.isSink(sink) } } -from TTConfig c, DataFlow::Node source, DataFlow::Node sink, string s -where - c.hasFlow(source, sink) and - s = sink.toString() -select s order by s +from TTConfig c, DataFlow::Node source, DataFlow::Node sink +where c.hasFlow(source, sink) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected index 7c1c2b73e46..d46b2550bff 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.expected @@ -215,6 +215,18 @@ edges | GlobalDataFlow.cs:377:16:377:21 | access to local variable sink11 | GlobalDataFlow.cs:159:22:159:43 | call to method TaintedParam | | GlobalDataFlow.cs:399:9:399:11 | value | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:193:22:193:32 | access to property OutProperty | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | nodes | Capture.cs:7:20:7:26 | tainted | | Capture.cs:9:9:13:9 | SSA capture def(tainted) | @@ -390,58 +402,77 @@ nodes | GlobalDataFlow.cs:399:9:399:11 | value | | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | | GlobalDataFlow.cs:410:22:410:35 | "taint source" | +| Splitting.cs:3:28:3:34 | tainted | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): false] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:17:8:31 | [b (line 3): true] call to method Return | +| Splitting.cs:8:24:8:30 | [b (line 3): false] access to parameter tainted | +| Splitting.cs:8:24:8:30 | [b (line 3): true] access to parameter tainted | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | #select -| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | -| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | -| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | -| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | -| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | -| GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | access to local variable sink12 | GlobalDataFlow.cs:329:22:329:35 | "taint source" | GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | -| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | -| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | -| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | -| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | -| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | -| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | -| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | -| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | -| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | -| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | -| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | -| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | -| GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | access to local variable sink24 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | -| GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | access to local variable sink25 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | -| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | access to local variable sink26 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | -| Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | -| Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | -| Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | -| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | -| Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | -| Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | -| Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | -| Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | -| Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | -| Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | -| Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | -| Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | -| Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | -| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | -| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | -| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | -| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | -| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | -| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | -| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | -| GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | -| GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | -| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | -| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | -| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | -| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | -| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | -| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | -| GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | -| GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | -| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | +| Capture.cs:12:19:12:24 | access to local variable sink27 | Capture.cs:7:20:7:26 | tainted | Capture.cs:12:19:12:24 | access to local variable sink27 | access to local variable sink27 | +| Capture.cs:21:23:21:28 | access to local variable sink28 | Capture.cs:7:20:7:26 | tainted | Capture.cs:21:23:21:28 | access to local variable sink28 | access to local variable sink28 | +| Capture.cs:30:19:30:24 | access to local variable sink29 | Capture.cs:7:20:7:26 | tainted | Capture.cs:30:19:30:24 | access to local variable sink29 | access to local variable sink29 | +| Capture.cs:60:15:60:20 | access to local variable sink30 | Capture.cs:57:22:57:35 | "taint source" | Capture.cs:60:15:60:20 | access to local variable sink30 | access to local variable sink30 | +| Capture.cs:72:15:72:20 | access to local variable sink31 | Capture.cs:67:26:67:39 | "taint source" | Capture.cs:72:15:72:20 | access to local variable sink31 | access to local variable sink31 | +| Capture.cs:81:15:81:20 | access to local variable sink32 | Capture.cs:77:22:77:35 | "taint source" | Capture.cs:81:15:81:20 | access to local variable sink32 | access to local variable sink32 | +| Capture.cs:109:15:109:20 | access to local variable sink33 | Capture.cs:101:25:101:31 | tainted | Capture.cs:109:15:109:20 | access to local variable sink33 | access to local variable sink33 | +| Capture.cs:121:15:121:20 | access to local variable sink34 | Capture.cs:101:25:101:31 | tainted | Capture.cs:121:15:121:20 | access to local variable sink34 | access to local variable sink34 | +| Capture.cs:130:15:130:20 | access to local variable sink35 | Capture.cs:101:25:101:31 | tainted | Capture.cs:130:15:130:20 | access to local variable sink35 | access to local variable sink35 | +| Capture.cs:137:15:137:20 | access to local variable sink36 | Capture.cs:101:25:101:31 | tainted | Capture.cs:137:15:137:20 | access to local variable sink36 | access to local variable sink36 | +| Capture.cs:145:15:145:20 | access to local variable sink37 | Capture.cs:101:25:101:31 | tainted | Capture.cs:145:15:145:20 | access to local variable sink37 | access to local variable sink37 | +| Capture.cs:171:15:171:20 | access to local variable sink38 | Capture.cs:101:25:101:31 | tainted | Capture.cs:171:15:171:20 | access to local variable sink38 | access to local variable sink38 | +| GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:18:15:18:29 | access to field SinkField0 | access to field SinkField0 | +| GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:26:15:26:32 | access to property SinkProperty0 | access to property SinkProperty0 | +| GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:44:50:44:59 | access to parameter sinkParam2 | access to parameter sinkParam2 | +| GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:71:15:71:19 | access to local variable sink0 | access to local variable sink0 | +| GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:73:15:73:19 | access to local variable sink1 | access to local variable sink1 | +| GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:76:15:76:19 | access to local variable sink2 | access to local variable sink2 | +| GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:79:15:79:19 | access to local variable sink3 | access to local variable sink3 | +| GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:81:15:81:20 | access to local variable sink13 | access to local variable sink13 | +| GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:83:15:83:20 | access to local variable sink14 | access to local variable sink14 | +| GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:85:15:85:20 | access to local variable sink15 | access to local variable sink15 | +| GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:87:15:87:20 | access to local variable sink16 | access to local variable sink16 | +| GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:89:15:89:20 | access to local variable sink17 | access to local variable sink17 | +| GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:91:15:91:20 | access to local variable sink18 | access to local variable sink18 | +| GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:94:15:94:20 | access to local variable sink21 | access to local variable sink21 | +| GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:97:15:97:20 | access to local variable sink22 | access to local variable sink22 | +| GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:132:15:132:19 | access to local variable sink4 | access to local variable sink4 | +| GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:140:15:140:19 | access to local variable sink5 | access to local variable sink5 | +| GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:150:15:150:19 | access to local variable sink6 | access to local variable sink6 | +| GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | GlobalDataFlow.cs:318:13:318:26 | "taint source" | GlobalDataFlow.cs:153:15:153:19 | access to local variable sink7 | access to local variable sink7 | +| GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | GlobalDataFlow.cs:323:13:323:26 | "taint source" | GlobalDataFlow.cs:156:15:156:19 | access to local variable sink8 | access to local variable sink8 | +| GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | GlobalDataFlow.cs:329:22:329:35 | "taint source" | GlobalDataFlow.cs:158:15:158:20 | access to local variable sink12 | access to local variable sink12 | +| GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:160:15:160:20 | access to local variable sink23 | access to local variable sink23 | +| GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | GlobalDataFlow.cs:175:35:175:48 | "taint source" | GlobalDataFlow.cs:177:15:177:19 | access to local variable sink9 | access to local variable sink9 | +| GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | GlobalDataFlow.cs:313:16:313:29 | "taint source" | GlobalDataFlow.cs:186:15:186:20 | access to local variable sink10 | access to local variable sink10 | +| GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | GlobalDataFlow.cs:410:22:410:35 | "taint source" | GlobalDataFlow.cs:194:15:194:20 | access to local variable sink19 | access to local variable sink19 | +| GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:204:58:204:68 | access to parameter sinkParam10 | access to parameter sinkParam10 | +| GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:207:15:207:20 | access to local variable sink24 | access to local variable sink24 | +| GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:209:15:209:20 | access to local variable sink25 | access to local variable sink25 | +| GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:211:15:211:20 | access to local variable sink26 | access to local variable sink26 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:233:15:233:24 | access to parameter sinkParam0 | access to parameter sinkParam0 | +| GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:238:15:238:24 | access to parameter sinkParam1 | access to parameter sinkParam1 | +| GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:243:15:243:24 | access to parameter sinkParam3 | access to parameter sinkParam3 | +| GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:248:15:248:24 | access to parameter sinkParam4 | access to parameter sinkParam4 | +| GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:253:15:253:24 | access to parameter sinkParam5 | access to parameter sinkParam5 | +| GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:258:15:258:24 | access to parameter sinkParam6 | access to parameter sinkParam6 | +| GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:263:15:263:24 | access to parameter sinkParam7 | access to parameter sinkParam7 | +| GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:289:15:289:24 | access to parameter sinkParam8 | access to parameter sinkParam8 | +| GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:295:15:295:24 | access to parameter sinkParam9 | access to parameter sinkParam9 | +| GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | GlobalDataFlow.cs:201:39:201:45 | tainted | GlobalDataFlow.cs:301:15:301:25 | access to parameter sinkParam11 | access to parameter sinkParam11 | +| GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | GlobalDataFlow.cs:373:39:373:45 | tainted | GlobalDataFlow.cs:376:15:376:20 | access to local variable sink11 | access to local variable sink11 | +| GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | GlobalDataFlow.cs:17:27:17:40 | "taint source" | GlobalDataFlow.cs:399:41:399:46 | access to local variable sink20 | access to local variable sink20 | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): false] access to local variable x | [b (line 3): false] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:9:15:9:15 | [b (line 3): true] access to local variable x | [b (line 3): true] access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | +| Splitting.cs:11:19:11:19 | access to local variable x | Splitting.cs:3:28:3:34 | tainted | Splitting.cs:11:19:11:19 | access to local variable x | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql index 71975ecd111..e0eccb70461 100644 --- a/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql +++ b/csharp/ql/test/library-tests/dataflow/global/TaintTrackingPath.ql @@ -20,4 +20,4 @@ from TTConfig c, DataFlow::PathNode source, DataFlow::PathNode sink, string s where c.hasFlowPath(source, sink) and s = sink.toString() -select sink, s, source, sink order by s +select sink, source, sink, s diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected index b1ae50cefe4..63462bbad86 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.expected @@ -1,19 +1,23 @@ -| access to field SsaFieldSink0 | -| access to field SsaFieldSink1 | -| access to local variable sink0 | -| access to local variable sink40 | -| access to local variable sink41 | -| access to local variable sink42 | -| access to local variable sink43 | -| access to local variable sink67 | -| access to local variable sink68 | -| access to local variable sink70 | -| access to local variable sink71 | -| access to local variable sink72 | -| access to local variable ssaSink0 | -| access to local variable ssaSink1 | -| access to local variable ssaSink2 | -| access to local variable ssaSink3 | -| access to local variable ssaSink4 | -| access to local variable ssaSink5 | -| access to parameter tainted | +| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | +| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | +| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | +| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | +| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | +| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | +| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | +| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | +| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | +| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | +| LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | +| SSA.cs:9:15:9:22 | access to local variable ssaSink0 | +| SSA.cs:25:15:25:22 | access to local variable ssaSink1 | +| SSA.cs:43:15:43:22 | access to local variable ssaSink2 | +| SSA.cs:60:15:60:22 | access to local variable ssaSink3 | +| SSA.cs:69:15:69:34 | access to field SsaFieldSink0 | +| SSA.cs:98:15:98:22 | access to local variable ssaSink4 | +| SSA.cs:124:15:124:34 | access to field SsaFieldSink1 | +| SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | +| Splitting.cs:27:19:27:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql b/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql index d51032520e6..4fec5b6c67a 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlow.ql @@ -1,9 +1,15 @@ import csharp import Common +import semmle.code.csharp.controlflow.Guards -from MyFlowSource source, Access target, string s +predicate step(DataFlow::Node pred, DataFlow::Node succ) { + DataFlow::localFlowStep(pred, succ) and + not succ instanceof NullGuardedDataFlowNode +} + +from MyFlowSource source, DataFlow::Node sink, Access target where - DataFlow::localFlowStep+(source, DataFlow::exprNode(target)) and - exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = target) and - s = target.toString() -select s order by s + step+(source, sink) and + sink = DataFlow::exprNode(target) and + exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = target) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 777b702ef10..1abc65684c6 100644 --- a/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -14,6 +14,7 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | +| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | @@ -48,18 +49,25 @@ | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | -| LocalDataFlow.cs:96:29:96:31 | "a" | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:29:100:33 | "abc" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | -| LocalDataFlow.cs:100:37:100:41 | "def" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | +| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | @@ -638,3 +646,74 @@ | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:5:17:5:23 | access to parameter tainted | Splitting.cs:5:13:5:23 | SSA def(x) | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): false] access to parameter b | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): true] access to parameter b | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | +| Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | [b (line 17): true] access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | +| Splitting.cs:19:17:19:18 | "" | Splitting.cs:19:13:19:18 | SSA def(x) | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): false] access to parameter b | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): true] access to parameter b | +| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | +| Splitting.cs:23:17:23:30 | [b (line 17): true] "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | +| Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | +| Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | +| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | +| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | +| Splitting.cs:37:13:37:15 | [b (line 32): false] "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | +| Splitting.cs:37:13:37:15 | [b (line 32): true] "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | +| Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | +| Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): false] access to parameter b | +| Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): true] access to parameter b | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:39:15:39:25 | [b (line 32): true] ... ? ... : ... | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:23:39:25 | [b (line 32): false] "c" | Splitting.cs:39:15:39:25 | [b (line 32): false] ... ? ... : ... | +| Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): false] (...) ... | +| Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): true] (...) ... | +| Splitting.cs:41:19:41:21 | [b (line 32): false] "d" | Splitting.cs:41:15:41:21 | [b (line 32): false] ... = ... | +| Splitting.cs:41:19:41:21 | [b (line 32): true] "d" | Splitting.cs:41:15:41:21 | [b (line 32): true] ... = ... | +| Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | +| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | +| Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): false] access to parameter b | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): true] access to parameter b | +| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): true] access to local variable x | +| Splitting.cs:50:17:50:21 | [b (line 46): true] "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | +| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | +| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | +| Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | +| Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | +| Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): false] access to local variable z | +| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): true] access to local variable z | +| Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:54:17:54:23 | [b (line 46): false] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | +| Splitting.cs:54:17:54:23 | [b (line 46): true] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | +| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): false] access to local variable x | +| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): true] access to local variable x | +| Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | +| Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | +| Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | +| Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): true] access to local variable y | +| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): false] access to local variable s | +| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): true] access to local variable s | diff --git a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs index 242725aa7c2..154b4d5fcb9 100644 --- a/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs +++ b/csharp/ql/test/library-tests/dataflow/local/LocalDataFlow.cs @@ -46,7 +46,7 @@ namespace System.Runtime.Serialization /// public class LocalDataFlow { - public async void M() + public async void M(bool b) { // Assignment, tainted var sink0 = "taint source"; @@ -93,11 +93,11 @@ public class LocalDataFlow Check(nonSink0); // Conditional expression, tainted - var sink7 = 1 > 2 ? "a" : sink6; + var sink7 = b ? "a" : sink6; Check(sink7); // Conditional expression, not tainted - nonSink0 = 4 == 2 ? "abc" : "def"; + nonSink0 = b ? "abc" : "def"; Check(nonSink0); // Cast, tainted diff --git a/csharp/ql/test/library-tests/dataflow/local/Splitting.cs b/csharp/ql/test/library-tests/dataflow/local/Splitting.cs new file mode 100644 index 00000000000..531e61f7963 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/local/Splitting.cs @@ -0,0 +1,66 @@ +class Splitting +{ + void M1(bool b, string tainted) + { + var x = tainted; + if (b) + { + Check(x); + if (x == null) + return; + } + Check(x); + if (b) + Check(x); + } + + void M2(bool b) + { + var x = ""; + if (b) + { + Check(x); + x = "taint source"; + } + Check(x); + if (b) + Check(x); + else + Check(x); + } + + void M3(bool b) + { + var x = ""; + if (b) + x = "a"; + x = "b"; + Check(x); + Check(b ? x : "c"); + Check((object)x); + Check(x = "d"); + if (b) + return; + } + + void M4(bool b) + { + var x = ""; + if (b) + x = "abc"; + var y = new string[] { "a" }; + y[0] = "b"; + x = x + y[0]; + var z = x == ""; + z = !z; + x = $"c{x}"; + x = (x, y).Item1; + foreach (var s in y) + Check(s); + if (b) + return; + } + + string Field; + static void Check(T x) { } +} diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected index 3ef16a3f828..ba3d91130f2 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.expected @@ -1,72 +1,77 @@ -| access to field SsaFieldSink0 | -| access to field SsaFieldSink1 | -| access to local variable sink0 | -| access to local variable sink1 | -| access to local variable sink10 | -| access to local variable sink11 | -| access to local variable sink12 | -| access to local variable sink13 | -| access to local variable sink14 | -| access to local variable sink15 | -| access to local variable sink16 | -| access to local variable sink17 | -| access to local variable sink18 | -| access to local variable sink19 | -| access to local variable sink2 | -| access to local variable sink20 | -| access to local variable sink21 | -| access to local variable sink22 | -| access to local variable sink23 | -| access to local variable sink24 | -| access to local variable sink25 | -| access to local variable sink26 | -| access to local variable sink27 | -| access to local variable sink28 | -| access to local variable sink29 | -| access to local variable sink3 | -| access to local variable sink30 | -| access to local variable sink31 | -| access to local variable sink32 | -| access to local variable sink33 | -| access to local variable sink34 | -| access to local variable sink35 | -| access to local variable sink36 | -| access to local variable sink40 | -| access to local variable sink41 | -| access to local variable sink42 | -| access to local variable sink43 | -| access to local variable sink45 | -| access to local variable sink46 | -| access to local variable sink47 | -| access to local variable sink48 | -| access to local variable sink49 | -| access to local variable sink5 | -| access to local variable sink50 | -| access to local variable sink51 | -| access to local variable sink52 | -| access to local variable sink53 | -| access to local variable sink54 | -| access to local variable sink6 | -| access to local variable sink60 | -| access to local variable sink61 | -| access to local variable sink62 | -| access to local variable sink63 | -| access to local variable sink64 | -| access to local variable sink65 | -| access to local variable sink66 | -| access to local variable sink67 | -| access to local variable sink68 | -| access to local variable sink69 | -| access to local variable sink7 | -| access to local variable sink70 | -| access to local variable sink71 | -| access to local variable sink72 | -| access to local variable sink8 | -| access to local variable sink9 | -| access to local variable ssaSink0 | -| access to local variable ssaSink1 | -| access to local variable ssaSink2 | -| access to local variable ssaSink3 | -| access to local variable ssaSink4 | -| access to local variable ssaSink5 | -| access to parameter tainted | +| LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | +| LocalDataFlow.cs:62:15:62:19 | access to local variable sink1 | +| LocalDataFlow.cs:71:15:71:19 | access to local variable sink2 | +| LocalDataFlow.cs:81:15:81:19 | access to local variable sink5 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | +| LocalDataFlow.cs:113:15:113:19 | access to local variable sink9 | +| LocalDataFlow.cs:121:15:121:20 | access to local variable sink10 | +| LocalDataFlow.cs:129:15:129:20 | access to local variable sink11 | +| LocalDataFlow.cs:137:15:137:20 | access to local variable sink14 | +| LocalDataFlow.cs:145:15:145:20 | access to local variable sink15 | +| LocalDataFlow.cs:148:15:148:20 | access to local variable sink16 | +| LocalDataFlow.cs:150:15:150:20 | access to local variable sink17 | +| LocalDataFlow.cs:152:15:152:20 | access to local variable sink18 | +| LocalDataFlow.cs:154:15:154:20 | access to local variable sink19 | +| LocalDataFlow.cs:156:15:156:20 | access to local variable sink45 | +| LocalDataFlow.cs:159:15:159:20 | access to local variable sink46 | +| LocalDataFlow.cs:161:15:161:20 | access to local variable sink47 | +| LocalDataFlow.cs:163:15:163:20 | access to local variable sink49 | +| LocalDataFlow.cs:165:15:165:20 | access to local variable sink50 | +| LocalDataFlow.cs:167:15:167:20 | access to local variable sink51 | +| LocalDataFlow.cs:169:15:169:20 | access to local variable sink52 | +| LocalDataFlow.cs:197:15:197:20 | access to local variable sink20 | +| LocalDataFlow.cs:199:15:199:20 | access to local variable sink21 | +| LocalDataFlow.cs:201:15:201:20 | access to local variable sink22 | +| LocalDataFlow.cs:211:15:211:20 | access to local variable sink23 | +| LocalDataFlow.cs:219:15:219:20 | access to local variable sink24 | +| LocalDataFlow.cs:227:15:227:20 | access to local variable sink25 | +| LocalDataFlow.cs:235:15:235:20 | access to local variable sink26 | +| LocalDataFlow.cs:237:15:237:20 | access to local variable sink27 | +| LocalDataFlow.cs:239:15:239:20 | access to local variable sink28 | +| LocalDataFlow.cs:241:15:241:20 | access to local variable sink29 | +| LocalDataFlow.cs:243:15:243:20 | access to local variable sink30 | +| LocalDataFlow.cs:259:15:259:20 | access to local variable sink31 | +| LocalDataFlow.cs:261:15:261:20 | access to local variable sink32 | +| LocalDataFlow.cs:271:15:271:20 | access to local variable sink33 | +| LocalDataFlow.cs:273:15:273:20 | access to local variable sink48 | +| LocalDataFlow.cs:283:15:283:20 | access to local variable sink34 | +| LocalDataFlow.cs:285:15:285:20 | access to local variable sink35 | +| LocalDataFlow.cs:288:15:288:20 | access to local variable sink36 | +| LocalDataFlow.cs:300:15:300:20 | access to local variable sink40 | +| LocalDataFlow.cs:302:15:302:20 | access to local variable sink41 | +| LocalDataFlow.cs:304:15:304:20 | access to local variable sink42 | +| LocalDataFlow.cs:306:15:306:20 | access to local variable sink43 | +| LocalDataFlow.cs:321:15:321:19 | access to local variable sink3 | +| LocalDataFlow.cs:323:15:323:20 | access to local variable sink12 | +| LocalDataFlow.cs:325:15:325:20 | access to local variable sink13 | +| LocalDataFlow.cs:339:15:339:20 | access to local variable sink53 | +| LocalDataFlow.cs:341:15:341:20 | access to local variable sink54 | +| LocalDataFlow.cs:355:15:355:20 | access to local variable sink60 | +| LocalDataFlow.cs:364:19:364:24 | access to local variable sink61 | +| LocalDataFlow.cs:366:15:366:20 | access to local variable sink62 | +| LocalDataFlow.cs:368:15:368:20 | access to local variable sink63 | +| LocalDataFlow.cs:370:15:370:20 | access to local variable sink64 | +| LocalDataFlow.cs:372:15:372:20 | access to local variable sink65 | +| LocalDataFlow.cs:374:15:374:20 | access to local variable sink66 | +| LocalDataFlow.cs:392:15:392:20 | access to local variable sink67 | +| LocalDataFlow.cs:394:15:394:20 | access to local variable sink68 | +| LocalDataFlow.cs:404:15:404:20 | access to local variable sink69 | +| LocalDataFlow.cs:412:15:412:20 | access to local variable sink70 | +| LocalDataFlow.cs:420:19:420:24 | access to local variable sink71 | +| LocalDataFlow.cs:430:23:430:28 | access to local variable sink72 | +| LocalDataFlow.cs:466:15:466:21 | access to parameter tainted | +| SSA.cs:9:15:9:22 | access to local variable ssaSink0 | +| SSA.cs:25:15:25:22 | access to local variable ssaSink1 | +| SSA.cs:43:15:43:22 | access to local variable ssaSink2 | +| SSA.cs:60:15:60:22 | access to local variable ssaSink3 | +| SSA.cs:69:15:69:34 | access to field SsaFieldSink0 | +| SSA.cs:98:15:98:22 | access to local variable ssaSink4 | +| SSA.cs:124:15:124:34 | access to field SsaFieldSink1 | +| SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | +| Splitting.cs:27:19:27:19 | access to local variable x | diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql index f7b5e4dab88..faf328c17ea 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTracking.ql @@ -1,9 +1,15 @@ import csharp import Common +import semmle.code.csharp.controlflow.Guards -from MyFlowSource source, Access sink, string s +predicate step(DataFlow::Node pred, DataFlow::Node succ) { + TaintTracking::localTaintStep(pred, succ) and + not succ instanceof NullGuardedDataFlowNode +} + +from MyFlowSource source, DataFlow::Node sink, Access target where - TaintTracking::localTaintStep+(source, DataFlow::exprNode(sink)) and - exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = sink) and - s = sink.toString() -select s order by s + step+(source, sink) and + sink = DataFlow::exprNode(target) and + exists(MethodCall mc | mc.getTarget().getName() = "Check" and mc.getAnArgument() = target) +select sink diff --git a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected index 7d41dc3ad68..0db00060530 100644 --- a/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected +++ b/csharp/ql/test/library-tests/dataflow/local/TaintTrackingStep.expected @@ -14,6 +14,7 @@ | Capture.cs:58:21:58:21 | 1 | Capture.cs:58:17:58:21 | SSA def(i) | | Capture.cs:61:17:61:17 | 1 | Capture.cs:61:13:61:17 | SSA def(i) | | Capture.cs:63:9:63:17 | SSA call def(i) | Capture.cs:64:13:64:13 | access to local variable i | +| LocalDataFlow.cs:49:30:49:30 | b | LocalDataFlow.cs:96:21:96:21 | access to parameter b | | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | | LocalDataFlow.cs:52:21:52:34 | "taint source" | LocalDataFlow.cs:52:13:52:34 | SSA def(sink0) | | LocalDataFlow.cs:53:15:53:19 | access to local variable sink0 | LocalDataFlow.cs:61:18:61:22 | access to local variable sink0 | @@ -64,24 +65,28 @@ | LocalDataFlow.cs:85:15:85:22 | access to local variable nonSink0 | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | | LocalDataFlow.cs:88:22:88:26 | access to local variable sink5 | LocalDataFlow.cs:88:13:88:27 | SSA def(sink6) | -| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | +| LocalDataFlow.cs:89:15:89:19 | access to local variable sink6 | LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | LocalDataFlow.cs:93:15:93:22 | access to local variable nonSink0 | | LocalDataFlow.cs:92:21:92:28 | access to local variable nonSink0 | LocalDataFlow.cs:92:9:92:29 | SSA def(nonSink0) | -| LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | -| LocalDataFlow.cs:96:21:96:21 | 1 | LocalDataFlow.cs:96:21:96:25 | ... > ... | -| LocalDataFlow.cs:96:21:96:25 | ... > ... | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:39 | SSA def(sink7) | -| LocalDataFlow.cs:96:25:96:25 | 2 | LocalDataFlow.cs:96:21:96:25 | ... > ... | -| LocalDataFlow.cs:96:29:96:31 | "a" | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:96:35:96:39 | access to local variable sink6 | LocalDataFlow.cs:96:21:96:39 | ... ? ... : ... | -| LocalDataFlow.cs:97:15:97:19 | access to local variable sink7 | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | -| LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | -| LocalDataFlow.cs:100:20:100:20 | 4 | LocalDataFlow.cs:100:20:100:25 | ... == ... | -| LocalDataFlow.cs:100:20:100:25 | ... == ... | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | -| LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | LocalDataFlow.cs:100:9:100:41 | SSA def(nonSink0) | -| LocalDataFlow.cs:100:25:100:25 | 2 | LocalDataFlow.cs:100:20:100:25 | ... == ... | -| LocalDataFlow.cs:100:29:100:33 | "abc" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | -| LocalDataFlow.cs:100:37:100:41 | "def" | LocalDataFlow.cs:100:20:100:41 | ... ? ... : ... | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | +| LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | +| LocalDataFlow.cs:96:21:96:21 | access to parameter b | LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): false] SSA def(sink7) | +| LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | LocalDataFlow.cs:96:13:96:35 | [b (line 49): true] SSA def(sink7) | +| LocalDataFlow.cs:96:25:96:27 | [b (line 49): true] "a" | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:96:31:96:35 | [b (line 49): false] access to local variable sink6 | LocalDataFlow.cs:96:21:96:35 | ... ? ... : ... | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): false] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:97:15:97:19 | [b (line 49): true] access to local variable sink7 | LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | +| LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | +| LocalDataFlow.cs:100:9:100:36 | SSA phi(sink7) | LocalDataFlow.cs:104:29:104:33 | access to local variable sink7 | +| LocalDataFlow.cs:100:20:100:20 | [b (line 49): false] access to parameter b | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:20 | [b (line 49): true] access to parameter b | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | LocalDataFlow.cs:100:9:100:36 | SSA def(nonSink0) | +| LocalDataFlow.cs:100:24:100:28 | "abc" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): true] ... ? ... : ... | +| LocalDataFlow.cs:100:32:100:36 | "def" | LocalDataFlow.cs:100:20:100:36 | [b (line 49): false] ... ? ... : ... | | LocalDataFlow.cs:101:15:101:22 | access to local variable nonSink0 | LocalDataFlow.cs:108:32:108:39 | access to local variable nonSink0 | | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | LocalDataFlow.cs:105:15:105:19 | access to local variable sink8 | | LocalDataFlow.cs:104:21:104:33 | (...) ... | LocalDataFlow.cs:104:13:104:33 | SSA def(sink8) | @@ -802,3 +807,105 @@ | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:176:21:176:28 | access to local variable ssaSink5 | | SSA.cs:177:21:177:28 | access to local variable ssaSink5 | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | | SSA.cs:180:9:180:24 | SSA phi(ssaSink5) | SSA.cs:180:15:180:22 | access to local variable ssaSink5 | +| Splitting.cs:3:18:3:18 | b | Splitting.cs:6:13:6:13 | access to parameter b | +| Splitting.cs:3:28:3:34 | tainted | Splitting.cs:5:17:5:23 | access to parameter tainted | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | +| Splitting.cs:5:13:5:23 | SSA def(x) | Splitting.cs:12:15:12:15 | [b (line 3): false] access to local variable x | +| Splitting.cs:5:17:5:23 | access to parameter tainted | Splitting.cs:5:13:5:23 | SSA def(x) | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): false] access to parameter b | +| Splitting.cs:6:13:6:13 | access to parameter b | Splitting.cs:13:13:13:13 | [b (line 3): true] access to parameter b | +| Splitting.cs:8:19:8:19 | [b (line 3): true] access to local variable x | Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | +| Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:9:17:9:25 | [b (line 3): true] ... == ... | +| Splitting.cs:9:17:9:17 | [b (line 3): true] access to local variable x | Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | +| Splitting.cs:12:15:12:15 | [b (line 3): true] access to local variable x | Splitting.cs:14:19:14:19 | access to local variable x | +| Splitting.cs:17:18:17:18 | b | Splitting.cs:20:13:20:13 | access to parameter b | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:22:19:22:19 | [b (line 17): true] access to local variable x | +| Splitting.cs:19:13:19:18 | SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | +| Splitting.cs:19:17:19:18 | "" | Splitting.cs:19:13:19:18 | SSA def(x) | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): false] access to parameter b | +| Splitting.cs:20:13:20:13 | access to parameter b | Splitting.cs:26:13:26:13 | [b (line 17): true] access to parameter b | +| Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | +| Splitting.cs:23:17:23:30 | [b (line 17): true] "taint source" | Splitting.cs:23:13:23:30 | [b (line 17): true] SSA def(x) | +| Splitting.cs:25:15:25:15 | [b (line 17): false] access to local variable x | Splitting.cs:29:19:29:19 | access to local variable x | +| Splitting.cs:25:15:25:15 | [b (line 17): true] access to local variable x | Splitting.cs:27:19:27:19 | access to local variable x | +| Splitting.cs:32:18:32:18 | b | Splitting.cs:35:13:35:13 | access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | +| Splitting.cs:35:13:35:13 | access to parameter b | Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | +| Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | +| Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | +| Splitting.cs:37:13:37:15 | [b (line 32): false] "b" | Splitting.cs:37:9:37:15 | [b (line 32): false] SSA def(x) | +| Splitting.cs:37:13:37:15 | [b (line 32): true] "b" | Splitting.cs:37:9:37:15 | [b (line 32): true] SSA def(x) | +| Splitting.cs:38:15:38:15 | [b (line 32): false] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | +| Splitting.cs:38:15:38:15 | [b (line 32): true] access to local variable x | Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | Splitting.cs:39:15:39:25 | [b (line 32): false] ... ? ... : ... | +| Splitting.cs:39:15:39:15 | [b (line 32): false] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): false] access to parameter b | +| Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | Splitting.cs:39:15:39:25 | [b (line 32): true] ... ? ... : ... | +| Splitting.cs:39:15:39:15 | [b (line 32): true] access to parameter b | Splitting.cs:42:13:42:13 | [b (line 32): true] access to parameter b | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:39:15:39:25 | [b (line 32): true] ... ? ... : ... | +| Splitting.cs:39:19:39:19 | [b (line 32): true] access to local variable x | Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | +| Splitting.cs:39:23:39:25 | [b (line 32): false] "c" | Splitting.cs:39:15:39:25 | [b (line 32): false] ... ? ... : ... | +| Splitting.cs:40:23:40:23 | [b (line 32): false] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): false] (...) ... | +| Splitting.cs:40:23:40:23 | [b (line 32): true] access to local variable x | Splitting.cs:40:15:40:23 | [b (line 32): true] (...) ... | +| Splitting.cs:41:19:41:21 | [b (line 32): false] "d" | Splitting.cs:41:15:41:21 | [b (line 32): false] ... = ... | +| Splitting.cs:41:19:41:21 | [b (line 32): true] "d" | Splitting.cs:41:15:41:21 | [b (line 32): true] ... = ... | +| Splitting.cs:46:18:46:18 | b | Splitting.cs:49:13:49:13 | access to parameter b | +| Splitting.cs:48:13:48:18 | SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | +| Splitting.cs:48:17:48:18 | "" | Splitting.cs:48:13:48:18 | SSA def(x) | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): false] access to parameter b | +| Splitting.cs:49:13:49:13 | access to parameter b | Splitting.cs:60:13:60:13 | [b (line 46): true] access to parameter b | +| Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | Splitting.cs:53:13:53:13 | [b (line 46): true] access to local variable x | +| Splitting.cs:50:17:50:21 | [b (line 46): true] "abc" | Splitting.cs:50:13:50:21 | [b (line 46): true] SSA def(x) | +| Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | +| Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): false] SSA def(y) | +| Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | Splitting.cs:51:13:51:36 | [b (line 46): true] SSA def(y) | +| Splitting.cs:51:32:51:34 | [b (line 46): false] "a" | Splitting.cs:51:17:51:36 | [b (line 46): false] array creation of type String[] | +| Splitting.cs:51:32:51:34 | [b (line 46): true] "a" | Splitting.cs:51:17:51:36 | [b (line 46): true] array creation of type String[] | +| Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:52:9:52:12 | [b (line 46): false] access to array element | +| Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:52:9:52:12 | [b (line 46): true] access to array element | +| Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): false] "b" | Splitting.cs:52:9:52:9 | [b (line 46): false] access to local variable y | +| Splitting.cs:52:16:52:18 | [b (line 46): true] "b" | Splitting.cs:52:9:52:9 | [b (line 46): true] access to local variable y | +| Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:53:13:53:13 | [b (line 46): false] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | +| Splitting.cs:53:13:53:13 | [b (line 46): true] access to local variable x | Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | +| Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): false] SSA def(x) | +| Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | Splitting.cs:53:9:53:20 | [b (line 46): true] SSA def(x) | +| Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | Splitting.cs:53:17:53:20 | [b (line 46): false] access to array element | +| Splitting.cs:53:17:53:17 | [b (line 46): false] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | +| Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | Splitting.cs:53:17:53:20 | [b (line 46): true] access to array element | +| Splitting.cs:53:17:53:17 | [b (line 46): true] access to local variable y | Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | +| Splitting.cs:53:17:53:20 | [b (line 46): false] access to array element | Splitting.cs:53:13:53:20 | [b (line 46): false] ... + ... | +| Splitting.cs:53:17:53:20 | [b (line 46): true] access to array element | Splitting.cs:53:13:53:20 | [b (line 46): true] ... + ... | +| Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): false] access to local variable z | +| Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | Splitting.cs:55:14:55:14 | [b (line 46): true] access to local variable z | +| Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | Splitting.cs:54:17:54:23 | [b (line 46): false] ... == ... | +| Splitting.cs:54:17:54:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | +| Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | Splitting.cs:54:17:54:23 | [b (line 46): true] ... == ... | +| Splitting.cs:54:17:54:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | +| Splitting.cs:54:17:54:23 | [b (line 46): false] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): false] SSA def(z) | +| Splitting.cs:54:17:54:23 | [b (line 46): true] ... == ... | Splitting.cs:54:13:54:23 | [b (line 46): true] SSA def(z) | +| Splitting.cs:55:14:55:14 | [b (line 46): false] access to local variable z | Splitting.cs:55:13:55:14 | [b (line 46): false] !... | +| Splitting.cs:55:14:55:14 | [b (line 46): true] access to local variable z | Splitting.cs:55:13:55:14 | [b (line 46): true] !... | +| Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): false] access to local variable x | +| Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | Splitting.cs:57:14:57:14 | [b (line 46): true] access to local variable x | +| Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): false] SSA def(x) | +| Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | Splitting.cs:56:9:56:19 | [b (line 46): true] SSA def(x) | +| Splitting.cs:56:15:56:15 | [b (line 46): false] "c" | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | +| Splitting.cs:56:15:56:15 | [b (line 46): true] "c" | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | +| Splitting.cs:56:17:56:17 | [b (line 46): false] access to local variable x | Splitting.cs:56:13:56:19 | [b (line 46): false] $"..." | +| Splitting.cs:56:17:56:17 | [b (line 46): true] access to local variable x | Splitting.cs:56:13:56:19 | [b (line 46): true] $"..." | +| Splitting.cs:57:13:57:18 | [b (line 46): false] (..., ...) | Splitting.cs:57:13:57:24 | [b (line 46): false] access to field Item1 | +| Splitting.cs:57:13:57:18 | [b (line 46): true] (..., ...) | Splitting.cs:57:13:57:24 | [b (line 46): true] access to field Item1 | +| Splitting.cs:57:14:57:14 | [b (line 46): false] access to local variable x | Splitting.cs:57:13:57:18 | [b (line 46): false] (..., ...) | +| Splitting.cs:57:14:57:14 | [b (line 46): true] access to local variable x | Splitting.cs:57:13:57:18 | [b (line 46): true] (..., ...) | +| Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:57:13:57:18 | [b (line 46): false] (..., ...) | +| Splitting.cs:57:17:57:17 | [b (line 46): false] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | +| Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | Splitting.cs:57:13:57:18 | [b (line 46): true] (..., ...) | +| Splitting.cs:57:17:57:17 | [b (line 46): true] access to local variable y | Splitting.cs:58:27:58:27 | [b (line 46): true] access to local variable y | +| Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): false] access to local variable s | +| Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | Splitting.cs:59:19:59:19 | [b (line 46): true] access to local variable s | +| Splitting.cs:58:27:58:27 | [b (line 46): false] access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): false] SSA def(s) | +| Splitting.cs:58:27:58:27 | [b (line 46): true] access to local variable y | Splitting.cs:58:22:58:22 | [b (line 46): true] SSA def(s) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected new file mode 100644 index 00000000000..04b5215b610 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.expected @@ -0,0 +1,340 @@ +| Capture.cs:6:16:6:16 | SSA param(i) | Capture.cs:6:16:6:16 | i | +| Capture.cs:8:13:8:17 | SSA def(x) | Capture.cs:8:13:8:17 | Int32 x = ... | +| Capture.cs:10:16:27:9 | SSA def(a) | Capture.cs:10:16:27:9 | Action a = ... | +| Capture.cs:10:20:27:9 | SSA capture def(i) | Capture.cs:10:20:27:9 | (...) => ... | +| Capture.cs:13:13:13:17 | SSA def(i) | Capture.cs:13:13:13:17 | ... = ... | +| Capture.cs:15:13:15:17 | SSA def(x) | Capture.cs:15:13:15:17 | ... = ... | +| Capture.cs:17:17:17:21 | SSA def(y) | Capture.cs:17:17:17:21 | Int32 y = ... | +| Capture.cs:19:20:23:13 | SSA def(b) | Capture.cs:19:20:23:13 | Action b = ... | +| Capture.cs:19:24:23:13 | SSA capture def(x) | Capture.cs:19:24:23:13 | (...) => ... | +| Capture.cs:19:24:23:13 | SSA capture def(y) | Capture.cs:19:24:23:13 | (...) => ... | +| Capture.cs:29:13:29:17 | SSA def(z) | Capture.cs:29:13:29:17 | Int32 z = ... | +| Capture.cs:30:16:30:35 | SSA def(c) | Capture.cs:30:16:30:35 | Action c = ... | +| Capture.cs:30:28:30:32 | SSA def(z) | Capture.cs:30:28:30:32 | ... = ... | +| Capture.cs:32:9:32:11 | SSA call def(z) | Capture.cs:32:9:32:11 | delegate call | +| Capture.cs:37:9:37:13 | SSA def(z) | Capture.cs:37:9:37:13 | ... = ... | +| Capture.cs:38:9:38:11 | SSA call def(i) | Capture.cs:38:9:38:11 | delegate call | +| Capture.cs:38:9:38:11 | SSA call def(x) | Capture.cs:38:9:38:11 | delegate call | +| Capture.cs:43:9:43:13 | SSA def(x) | Capture.cs:43:9:43:13 | ... = ... | +| Capture.cs:44:9:44:12 | SSA call def(x) | Capture.cs:44:9:44:12 | call to method M | +| Capture.cs:50:20:50:20 | SSA param(a) | Capture.cs:50:20:50:20 | a | +| Capture.cs:52:16:52:43 | SSA def(b) | Capture.cs:52:16:52:43 | Action b = ... | +| Capture.cs:52:28:52:40 | SSA def(a) | Capture.cs:52:28:52:40 | ... = ... | +| Capture.cs:53:9:53:11 | SSA call def(a) | Capture.cs:53:9:53:11 | delegate call | +| Capture.cs:57:57:57:63 | SSA param(strings) | Capture.cs:57:57:57:63 | strings | +| Capture.cs:59:13:59:17 | SSA def(i) | Capture.cs:59:13:59:17 | Int32 i = ... | +| Capture.cs:60:27:60:38 | SSA def(e) | Capture.cs:60:27:60:38 | Func e = ... | +| Capture.cs:60:31:60:38 | SSA capture def(i) | Capture.cs:60:31:60:38 | (...) => ... | +| Capture.cs:60:36:60:38 | SSA def(i) | Capture.cs:60:36:60:38 | ...++ | +| Capture.cs:61:9:61:25 | SSA call def(i) | Capture.cs:61:9:61:25 | call to method Select | +| Capture.cs:65:45:65:51 | SSA param(strings) | Capture.cs:65:45:65:51 | strings | +| Capture.cs:67:13:67:19 | SSA def(c) | Capture.cs:67:13:67:19 | Char c = ... | +| Capture.cs:68:32:68:32 | SSA param(s) | Capture.cs:68:32:68:32 | s | +| Capture.cs:68:32:68:49 | SSA capture def(c) | Capture.cs:68:32:68:49 | (...) => ... | +| Capture.cs:69:9:69:62 | SSA capture def(c) | Capture.cs:69:9:69:62 | M | +| Capture.cs:69:25:69:25 | SSA param(s) | Capture.cs:69:25:69:25 | s | +| Capture.cs:73:67:73:73 | SSA param(strings) | Capture.cs:73:67:73:73 | strings | +| Capture.cs:75:13:75:17 | SSA def(i) | Capture.cs:75:13:75:17 | Int32 i = ... | +| Capture.cs:76:63:76:81 | SSA def(e) | Capture.cs:76:63:76:81 | Expression> e = ... | +| Capture.cs:76:67:76:81 | SSA capture def(i) | Capture.cs:76:67:76:81 | (...) => ... | +| Capture.cs:76:80:76:80 | SSA def(i) | Capture.cs:76:72:76:81 | call to method Inc | +| Capture.cs:77:9:77:25 | SSA call def(i) | Capture.cs:77:9:77:25 | call to method Select | +| Capture.cs:81:28:81:28 | SSA param(i) | Capture.cs:81:28:81:28 | i | +| Capture.cs:81:34:81:36 | SSA def(i) | Capture.cs:81:34:81:36 | ...++ | +| Capture.cs:83:65:83:71 | SSA param(strings) | Capture.cs:83:65:83:71 | strings | +| Capture.cs:85:13:85:20 | SSA def(b) | Capture.cs:85:13:85:20 | Boolean b = ... | +| Capture.cs:86:64:86:73 | SSA def(e) | Capture.cs:86:64:86:73 | Expression> e = ... | +| Capture.cs:86:68:86:73 | SSA capture def(b) | Capture.cs:86:68:86:73 | (...) => ... | +| Capture.cs:92:18:92:18 | SSA param(d) | Capture.cs:92:18:92:18 | d | +| Capture.cs:94:13:94:18 | SSA def(y) | Capture.cs:94:13:94:18 | Int32 y = ... | +| Capture.cs:96:12:100:9 | SSA capture def(y) | Capture.cs:96:12:100:9 | (...) => ... | +| Capture.cs:98:17:98:21 | SSA def(x) | Capture.cs:98:17:98:21 | Int32 x = ... | +| Capture.cs:105:13:105:17 | SSA def(z) | Capture.cs:105:13:105:17 | ... = ... | +| Capture.cs:114:13:114:18 | SSA def(a) | Capture.cs:114:13:114:18 | Int32 a = ... | +| Capture.cs:115:9:119:9 | SSA capture def(a) | Capture.cs:115:9:119:9 | M1 | +| Capture.cs:117:17:117:21 | SSA def(x) | Capture.cs:117:17:117:21 | Int32 x = ... | +| Capture.cs:125:13:125:17 | SSA def(b) | Capture.cs:125:13:125:17 | ... = ... | +| Capture.cs:130:13:130:18 | SSA def(c) | Capture.cs:130:13:130:18 | Int32 c = ... | +| Capture.cs:133:13:133:17 | SSA def(c) | Capture.cs:133:13:133:17 | ... = ... | +| Capture.cs:136:9:136:12 | SSA call def(c) | Capture.cs:136:9:136:12 | call to local function M3 | +| Capture.cs:139:13:139:18 | SSA def(d) | Capture.cs:139:13:139:18 | Int32 d = ... | +| Capture.cs:142:13:142:17 | SSA def(d) | Capture.cs:142:13:142:17 | ... = ... | +| Capture.cs:144:9:144:12 | SSA call def(d) | Capture.cs:144:9:144:12 | call to local function M4 | +| Capture.cs:148:9:152:9 | SSA capture def(e) | Capture.cs:148:9:152:9 | M5 | +| Capture.cs:154:13:154:18 | SSA def(f) | Capture.cs:154:13:154:18 | Int32 f = ... | +| Capture.cs:163:9:166:9 | SSA capture def(g) | Capture.cs:163:9:166:9 | M7 | +| Capture.cs:171:13:171:17 | SSA def(h) | Capture.cs:171:13:171:17 | ... = ... | +| Capture.cs:174:17:174:21 | SSA def(h) | Capture.cs:174:17:174:21 | ... = ... | +| Capture.cs:176:13:176:16 | SSA call def(h) | Capture.cs:176:13:176:16 | call to local function M9 | +| Capture.cs:182:17:182:21 | SSA def(i) | Capture.cs:182:17:182:21 | Int32 i = ... | +| Capture.cs:183:13:186:13 | SSA capture def(i) | Capture.cs:183:13:186:13 | M11 | +| Capture.cs:188:13:188:17 | SSA def(i) | Capture.cs:188:13:188:17 | ... = ... | +| Capture.cs:197:17:197:21 | SSA def(i) | Capture.cs:197:17:197:21 | Int32 i = ... | +| Capture.cs:198:28:198:44 | SSA def(eh) | Capture.cs:198:28:198:44 | MyEventHandler eh = ... | +| Capture.cs:198:33:198:44 | SSA capture def(i) | Capture.cs:198:33:198:44 | (...) => ... | +| Capture.cs:203:28:203:45 | SSA def(eh2) | Capture.cs:203:28:203:45 | MyEventHandler eh2 = ... | +| Capture.cs:203:34:203:45 | SSA capture def(i) | Capture.cs:203:34:203:45 | (...) => ... | +| Capture.cs:209:17:209:21 | SSA def(i) | Capture.cs:209:17:209:21 | Int32 i = ... | +| Capture.cs:210:24:210:59 | SSA def(p) | Capture.cs:210:24:210:59 | Process p = ... | +| Capture.cs:212:30:212:71 | SSA def(exited) | Capture.cs:212:30:212:71 | EventHandler exited = ... | +| Capture.cs:212:39:212:71 | SSA capture def(i) | Capture.cs:212:39:212:71 | (...) => ... | +| Capture.cs:231:9:231:49 | SSA capture def(i) | Capture.cs:231:9:231:49 | M2 | +| Capture.cs:232:9:232:13 | SSA def(i) | Capture.cs:232:9:232:13 | ... = ... | +| Capture.cs:235:21:235:25 | SSA def(i) | Capture.cs:235:21:235:25 | ... = ... | +| Capture.cs:236:9:236:12 | SSA call def(i) | Capture.cs:236:9:236:12 | call to local function M3 | +| Consistency.cs:7:25:7:25 | SSA param(b) | Consistency.cs:7:25:7:25 | b | +| Consistency.cs:15:17:15:21 | SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | +| Consistency.cs:15:17:15:21 | [finally: exception(Exception)] SSA def(i) | Consistency.cs:15:17:15:21 | Int32 i = ... | +| Consistency.cs:25:29:25:29 | SSA def(c) | Consistency.cs:25:9:25:30 | call to method Out | +| Consistency.cs:25:29:25:29 | SSA qualifier def(c.Field) | Consistency.cs:25:9:25:30 | call to method Out | +| Consistency.cs:32:9:32:29 | SSA def(c) | Consistency.cs:32:9:32:29 | ... = ... | +| Consistency.cs:39:28:39:32 | SSA def(i) | Consistency.cs:39:28:39:32 | ... = ... | +| Consistency.cs:44:11:44:11 | SSA def(s) | Consistency.cs:44:11:44:11 | S s | +| Consistency.cs:49:30:49:30 | SSA param(a) | Consistency.cs:49:30:49:30 | a | +| Consistency.cs:49:37:49:37 | SSA param(i) | Consistency.cs:49:37:49:37 | i | +| Consistency.cs:51:20:51:20 | SSA param(a) | Consistency.cs:51:20:51:20 | a | +| Consistency.cs:56:17:56:40 | SSA def(k) | Consistency.cs:56:17:56:40 | Int32 k = ... | +| Consistency.cs:57:9:57:13 | SSA def(k) | Consistency.cs:57:9:57:13 | ... = ... | +| Consistency.cs:58:9:58:13 | SSA def(k) | Consistency.cs:58:9:58:13 | ... = ... | +| DefUse.cs:3:26:3:26 | SSA param(w) | DefUse.cs:3:26:3:26 | w | +| DefUse.cs:5:13:5:17 | SSA def(x) | DefUse.cs:5:13:5:17 | Int32 x = ... | +| DefUse.cs:6:14:6:19 | SSA def(y) | DefUse.cs:6:14:6:19 | Int64 y = ... | +| DefUse.cs:13:13:13:18 | SSA def(y) | DefUse.cs:13:13:13:18 | ... = ... | +| DefUse.cs:18:13:18:18 | SSA def(y) | DefUse.cs:18:13:18:18 | ... = ... | +| DefUse.cs:19:13:19:18 | SSA def(w) | DefUse.cs:19:13:19:18 | ... = ... | +| DefUse.cs:28:13:28:18 | SSA def(y) | DefUse.cs:28:13:28:18 | ... = ... | +| DefUse.cs:29:13:29:18 | SSA def(w) | DefUse.cs:29:13:29:18 | ... = ... | +| DefUse.cs:39:13:39:18 | SSA def(y) | DefUse.cs:39:13:39:18 | ... = ... | +| DefUse.cs:44:13:44:17 | SSA def(z) | DefUse.cs:44:13:44:17 | Int32 z = ... | +| DefUse.cs:47:23:47:23 | SSA def(z) | DefUse.cs:47:9:47:24 | call to method outMethod | +| DefUse.cs:50:23:50:23 | SSA def(z) | DefUse.cs:50:9:50:24 | call to method refMethod | +| DefUse.cs:53:9:53:17 | SSA def(this.Field) | DefUse.cs:53:9:53:17 | ... = ... | +| DefUse.cs:56:9:56:16 | SSA def(this.Prop) | DefUse.cs:56:9:56:16 | ... = ... | +| DefUse.cs:59:13:59:17 | SSA def(i) | DefUse.cs:59:13:59:17 | Int32 i = ... | +| DefUse.cs:63:9:63:18 | SSA def(this.Field2) | DefUse.cs:63:9:63:18 | ... = ... | +| DefUse.cs:66:9:66:18 | SSA def(this.Field3) | DefUse.cs:66:9:66:18 | ... = ... | +| DefUse.cs:67:19:67:27 | SSA def(tc) | DefUse.cs:67:19:67:27 | TestClass tc = ... | +| DefUse.cs:71:9:71:13 | SSA def(i) | DefUse.cs:71:9:71:13 | ... = ... | +| DefUse.cs:72:9:72:11 | SSA def(i) | DefUse.cs:72:9:72:11 | ...++ | +| DefUse.cs:75:9:75:13 | SSA def(i) | DefUse.cs:75:9:75:13 | ... = ... | +| DefUse.cs:76:9:76:11 | SSA def(i) | DefUse.cs:76:9:76:11 | ...-- | +| DefUse.cs:79:13:79:18 | SSA def(x1) | DefUse.cs:79:13:79:18 | Int32 x1 = ... | +| DefUse.cs:80:30:80:31 | SSA def(x1) | DefUse.cs:80:16:80:32 | call to method refMethod | +| DefUse.cs:83:13:83:18 | SSA def(x2) | DefUse.cs:83:13:83:18 | Int32 x2 = ... | +| DefUse.cs:85:15:85:16 | SSA def(x2) | DefUse.cs:84:9:86:17 | call to method refOutMethod | +| DefUse.cs:89:13:89:18 | SSA def(x3) | DefUse.cs:89:13:89:18 | Int32 x3 = ... | +| DefUse.cs:92:15:92:16 | SSA def(x3) | DefUse.cs:91:9:93:17 | call to method refOutMethod | +| DefUse.cs:93:15:93:16 | SSA def(x4) | DefUse.cs:91:9:93:17 | call to method refOutMethod | +| DefUse.cs:97:13:97:18 | SSA def(x5) | DefUse.cs:97:13:97:18 | Int32 x5 = ... | +| DefUse.cs:101:13:101:23 | SSA def(x5) | DefUse.cs:101:13:101:23 | ... = ... | +| DefUse.cs:104:9:104:15 | SSA def(x5) | DefUse.cs:104:9:104:15 | ... = ... | +| DefUse.cs:114:47:114:52 | SSA def(i) | DefUse.cs:114:47:114:52 | ... = ... | +| DefUse.cs:116:47:116:51 | SSA def(i) | DefUse.cs:116:47:116:51 | ... = ... | +| DefUse.cs:118:45:118:45 | SSA param(i) | DefUse.cs:118:45:118:45 | i | +| DefUse.cs:118:61:118:65 | SSA def(j) | DefUse.cs:118:61:118:65 | ... = ... | +| DefUse.cs:118:68:118:72 | SSA def(i) | DefUse.cs:118:68:118:72 | ... = ... | +| DefUse.cs:128:19:128:19 | SSA param(i) | DefUse.cs:128:19:128:19 | i | +| DefUse.cs:134:22:134:22 | SSA param(d) | DefUse.cs:134:22:134:22 | d | +| DefUse.cs:142:68:142:69 | SSA param(ie) | DefUse.cs:142:68:142:69 | ie | +| DefUse.cs:144:22:144:22 | SSA def(x) | DefUse.cs:144:22:144:22 | String x | +| DefUse.cs:155:9:155:18 | SSA def(this.Field4) | DefUse.cs:155:9:155:18 | ... = ... | +| DefUse.cs:160:10:160:16 | SSA entry def(this.Field4) | DefUse.cs:160:10:160:16 | FieldM2 | +| DefUse.cs:167:23:167:23 | SSA param(i) | DefUse.cs:167:23:167:23 | i | +| DefUse.cs:170:9:170:13 | SSA def(i) | DefUse.cs:170:9:170:13 | ... = ... | +| DefUse.cs:171:23:180:9 | SSA def(a) | DefUse.cs:171:23:180:9 | Action a = ... | +| DefUse.cs:173:13:173:17 | SSA def(i) | DefUse.cs:173:13:173:17 | ... = ... | +| DefUse.cs:175:32:179:13 | SSA capture def(i) | DefUse.cs:175:32:179:13 | (...) => ... | +| DefUse.cs:181:9:181:11 | SSA call def(i) | DefUse.cs:181:9:181:11 | delegate call | +| DefUse.cs:184:9:184:18 | SSA def(this.Field5) | DefUse.cs:184:9:184:18 | ... = ... | +| DefUse.cs:186:9:190:9 | SSA def(a) | DefUse.cs:186:9:190:9 | ... = ... | +| DefUse.cs:188:13:188:22 | SSA def(this.Field5) | DefUse.cs:188:13:188:22 | ... = ... | +| DefUse.cs:191:9:191:11 | SSA call def(this.Field5) | DefUse.cs:191:9:191:11 | delegate call | +| Example.cs:6:23:6:23 | SSA param(i) | Example.cs:6:23:6:23 | i | +| Example.cs:8:9:8:22 | SSA def(this.Field) | Example.cs:8:9:8:22 | ... = ... | +| Example.cs:11:13:11:30 | SSA def(this.Field) | Example.cs:11:13:11:30 | ... = ... | +| Example.cs:13:13:13:23 | SSA call def(this.Field) | Example.cs:13:13:13:23 | call to method SetField | +| Example.cs:18:16:18:16 | SSA param(p) | Example.cs:18:16:18:16 | p | +| Example.cs:18:24:18:24 | SSA param(b) | Example.cs:18:24:18:24 | b | +| Example.cs:23:13:23:17 | SSA def(p) | Example.cs:23:13:23:17 | ... = ... | +| Fields.cs:16:17:16:17 | SSA entry def(this.xs) | Fields.cs:16:17:16:17 | F | +| Fields.cs:19:9:19:13 | SSA call def(this.xs) | Fields.cs:19:9:19:13 | call to method Upd | +| Fields.cs:20:9:20:14 | SSA def(x) | Fields.cs:20:9:20:14 | ... = ... | +| Fields.cs:22:13:22:17 | SSA call def(this.xs) | Fields.cs:22:13:22:17 | call to method Upd | +| Fields.cs:24:9:24:23 | SSA def(this.xs) | Fields.cs:24:9:24:23 | ... = ... | +| Fields.cs:28:17:28:17 | SSA entry def(Fields.stat) | Fields.cs:28:17:28:17 | G | +| Fields.cs:28:17:28:17 | SSA entry def(this.xs) | Fields.cs:28:17:28:17 | G | +| Fields.cs:30:13:30:28 | SSA def(f) | Fields.cs:30:13:30:28 | Fields f = ... | +| Fields.cs:30:13:30:28 | SSA qualifier def(f.xs) | Fields.cs:30:13:30:28 | Fields f = ... | +| Fields.cs:30:17:30:28 | SSA call def(Fields.stat) | Fields.cs:30:17:30:28 | object creation of type Fields | +| Fields.cs:34:9:34:16 | SSA call def(Fields.stat) | Fields.cs:34:9:34:16 | call to method F | +| Fields.cs:34:9:34:16 | SSA call def(f.xs) | Fields.cs:34:9:34:16 | call to method F | +| Fields.cs:34:9:34:16 | SSA call def(this.xs) | Fields.cs:34:9:34:16 | call to method F | +| Fields.cs:38:9:38:13 | SSA call def(Fields.stat) | Fields.cs:38:9:38:13 | call to method F | +| Fields.cs:38:9:38:13 | SSA call def(f.xs) | Fields.cs:38:9:38:13 | call to method F | +| Fields.cs:38:9:38:13 | SSA call def(this.xs) | Fields.cs:38:9:38:13 | call to method F | +| Fields.cs:42:9:42:23 | SSA def(this.xs) | Fields.cs:42:9:42:23 | ... = ... | +| Fields.cs:45:9:45:25 | SSA def(f.xs) | Fields.cs:45:9:45:25 | ... = ... | +| Fields.cs:47:9:47:14 | SSA def(z) | Fields.cs:47:9:47:14 | ... = ... | +| Fields.cs:49:13:49:28 | SSA def(f) | Fields.cs:49:13:49:28 | ... = ... | +| Fields.cs:49:13:49:28 | SSA qualifier def(f.xs) | Fields.cs:49:13:49:28 | ... = ... | +| Fields.cs:49:17:49:28 | SSA call def(Fields.stat) | Fields.cs:49:17:49:28 | object creation of type Fields | +| Fields.cs:51:9:51:20 | SSA call def(Fields.stat) | Fields.cs:51:9:51:20 | object creation of type Fields | +| Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | Fields.cs:61:17:61:17 | H | +| Fields.cs:63:16:63:28 | SSA untracked def(this.VolatileField) | Fields.cs:63:16:63:28 | this access | +| Fields.cs:69:21:69:33 | SSA untracked def(this.VolatileField) | Fields.cs:69:21:69:33 | this access | +| Fields.cs:71:17:71:35 | SSA untracked def(this.SingleAccessedField) | Fields.cs:71:17:71:35 | this access | +| Fields.cs:76:20:76:38 | SSA untracked def(this.SingleAccessedField) | Fields.cs:76:20:76:38 | this access | +| Fields.cs:77:13:77:45 | SSA def(f) | Fields.cs:77:13:77:45 | Fields f = ... | +| Fields.cs:78:23:78:54 | SSA def(a) | Fields.cs:78:23:78:54 | Action a = ... | +| Fields.cs:78:27:78:54 | SSA capture def(f) | Fields.cs:78:27:78:54 | (...) => ... | +| Fields.cs:79:23:79:35 | SSA def(b) | Fields.cs:79:23:79:35 | Action b = ... | +| Fields.cs:80:9:80:25 | SSA def(f.xs) | Fields.cs:80:9:80:25 | ... = ... | +| Fields.cs:81:9:81:11 | SSA call def(f.xs) | Fields.cs:81:9:81:11 | delegate call | +| Fields.cs:83:9:83:25 | SSA def(f.xs) | Fields.cs:83:9:83:25 | ... = ... | +| Fields.cs:85:9:85:22 | SSA def(this.xs) | Fields.cs:85:9:85:22 | ... = ... | +| Fields.cs:86:9:86:47 | SSA call def(f.xs) | Fields.cs:86:9:86:47 | call to method Select | +| Fields.cs:86:24:86:46 | SSA capture def(a) | Fields.cs:86:24:86:46 | (...) => ... | +| Fields.cs:87:9:87:22 | SSA def(this.xs) | Fields.cs:87:9:87:22 | ... = ... | +| Fields.cs:88:9:88:25 | SSA def(f.xs) | Fields.cs:88:9:88:25 | ... = ... | +| Fields.cs:89:24:89:46 | SSA capture def(b) | Fields.cs:89:24:89:46 | (...) => ... | +| Fields.cs:95:19:95:19 | SSA param(f) | Fields.cs:95:19:95:19 | f | +| Fields.cs:97:9:97:30 | SSA def(f.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:97:9:97:30 | SSA qualifier def(f.Field.Field.Field.Field) | Fields.cs:97:9:97:30 | ... = ... | +| Fields.cs:102:9:102:28 | SSA def(this.Field) | Fields.cs:102:9:102:28 | ... = ... | +| Fields.cs:107:33:107:33 | SSA param(f) | Fields.cs:107:33:107:33 | f | +| Fields.cs:109:10:109:10 | SSA entry def(this.Field) | Fields.cs:109:10:109:10 | K | +| Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field) | Fields.cs:109:10:109:10 | K | +| Fields.cs:109:10:109:10 | SSA entry def(this.Field.Field.xs) | Fields.cs:109:10:109:10 | K | +| Fields.cs:114:9:114:22 | SSA call def(this.Field) | Fields.cs:114:9:114:22 | call to method SetField | +| Fields.cs:114:9:114:22 | SSA call def(this.Field.Field) | Fields.cs:114:9:114:22 | call to method SetField | +| Fields.cs:114:9:114:22 | SSA qualifier def(this.Field.Field.xs) | Fields.cs:114:9:114:22 | call to method SetField | +| OutRef.cs:7:10:7:10 | SSA entry def(this.Field) | OutRef.cs:7:10:7:10 | M | +| OutRef.cs:9:13:9:17 | SSA def(j) | OutRef.cs:9:13:9:17 | Int32 j = ... | +| OutRef.cs:10:25:10:25 | SSA def(i) | OutRef.cs:10:9:10:33 | call to method OutRefM | +| OutRef.cs:10:32:10:32 | SSA def(j) | OutRef.cs:10:9:10:33 | call to method OutRefM | +| OutRef.cs:13:21:13:21 | SSA def(i) | OutRef.cs:13:9:13:33 | call to method OutRefM | +| OutRef.cs:13:28:13:32 | SSA def(this.Field) | OutRef.cs:13:9:13:33 | call to method OutRefM | +| OutRef.cs:16:21:16:25 | SSA def(this.Field) | OutRef.cs:16:9:16:37 | call to method OutRefM | +| OutRef.cs:18:13:18:28 | SSA def(t) | OutRef.cs:18:13:18:28 | OutRef t = ... | +| OutRef.cs:18:13:18:28 | SSA qualifier def(t.Field) | OutRef.cs:18:13:18:28 | OutRef t = ... | +| OutRef.cs:19:21:19:25 | SSA def(this.Field) | OutRef.cs:19:9:19:39 | call to method OutRefM | +| OutRef.cs:19:32:19:38 | SSA def(t.Field) | OutRef.cs:19:9:19:39 | call to method OutRefM | +| OutRef.cs:22:22:22:22 | SSA def(j) | OutRef.cs:22:9:22:30 | call to method OutRefM2 | +| OutRef.cs:24:29:24:29 | SSA def(j) | OutRef.cs:24:9:24:30 | call to method OutRefM3 | +| OutRef.cs:28:37:28:37 | SSA param(j) | OutRef.cs:28:37:28:37 | j | +| OutRef.cs:30:9:30:13 | SSA def(i) | OutRef.cs:30:9:30:13 | ... = ... | +| OutRef.cs:31:9:31:13 | SSA def(j) | OutRef.cs:31:9:31:13 | ... = ... | +| OutRef.cs:34:38:34:38 | SSA param(j) | OutRef.cs:34:38:34:38 | j | +| OutRef.cs:36:9:36:13 | SSA def(i) | OutRef.cs:36:9:36:13 | ... = ... | +| OutRef.cs:39:24:39:24 | SSA param(b) | OutRef.cs:39:24:39:24 | b | +| OutRef.cs:39:35:39:35 | SSA param(j) | OutRef.cs:39:35:39:35 | j | +| OutRef.cs:42:13:42:17 | SSA def(j) | OutRef.cs:42:13:42:17 | ... = ... | +| Patterns.cs:7:16:7:23 | SSA def(o) | Patterns.cs:7:16:7:23 | Object o = ... | +| Patterns.cs:8:18:8:23 | SSA def(i1) | Patterns.cs:8:18:8:23 | Int32 i1 | +| Patterns.cs:12:23:12:31 | SSA def(s1) | Patterns.cs:12:23:12:31 | String s1 | +| Patterns.cs:24:18:24:23 | SSA def(i2) | Patterns.cs:24:18:24:23 | Int32 i2 | +| Patterns.cs:27:18:27:23 | SSA def(i3) | Patterns.cs:27:18:27:23 | Int32 i3 | +| Patterns.cs:30:18:30:26 | SSA def(s2) | Patterns.cs:30:18:30:26 | String s2 | +| Properties.cs:16:17:16:17 | SSA entry def(this.xs) | Properties.cs:16:17:16:17 | F | +| Properties.cs:19:9:19:13 | SSA call def(this.xs) | Properties.cs:19:9:19:13 | call to method Upd | +| Properties.cs:20:9:20:14 | SSA def(x) | Properties.cs:20:9:20:14 | ... = ... | +| Properties.cs:22:13:22:17 | SSA call def(this.xs) | Properties.cs:22:13:22:17 | call to method Upd | +| Properties.cs:24:9:24:23 | SSA def(this.xs) | Properties.cs:24:9:24:23 | ... = ... | +| Properties.cs:28:17:28:17 | SSA entry def(Properties.stat) | Properties.cs:28:17:28:17 | G | +| Properties.cs:28:17:28:17 | SSA entry def(this.xs) | Properties.cs:28:17:28:17 | G | +| Properties.cs:30:13:30:32 | SSA def(f) | Properties.cs:30:13:30:32 | Properties f = ... | +| Properties.cs:30:13:30:32 | SSA qualifier def(f.xs) | Properties.cs:30:13:30:32 | Properties f = ... | +| Properties.cs:30:17:30:32 | SSA call def(Properties.stat) | Properties.cs:30:17:30:32 | object creation of type Properties | +| Properties.cs:34:9:34:16 | SSA call def(Properties.stat) | Properties.cs:34:9:34:16 | call to method F | +| Properties.cs:34:9:34:16 | SSA call def(f.xs) | Properties.cs:34:9:34:16 | call to method F | +| Properties.cs:34:9:34:16 | SSA call def(this.xs) | Properties.cs:34:9:34:16 | call to method F | +| Properties.cs:38:9:38:13 | SSA call def(Properties.stat) | Properties.cs:38:9:38:13 | call to method F | +| Properties.cs:38:9:38:13 | SSA call def(f.xs) | Properties.cs:38:9:38:13 | call to method F | +| Properties.cs:38:9:38:13 | SSA call def(this.xs) | Properties.cs:38:9:38:13 | call to method F | +| Properties.cs:42:9:42:23 | SSA def(this.xs) | Properties.cs:42:9:42:23 | ... = ... | +| Properties.cs:45:9:45:25 | SSA def(f.xs) | Properties.cs:45:9:45:25 | ... = ... | +| Properties.cs:47:9:47:14 | SSA def(z) | Properties.cs:47:9:47:14 | ... = ... | +| Properties.cs:49:13:49:32 | SSA def(f) | Properties.cs:49:13:49:32 | ... = ... | +| Properties.cs:49:13:49:32 | SSA qualifier def(f.xs) | Properties.cs:49:13:49:32 | ... = ... | +| Properties.cs:49:17:49:32 | SSA call def(Properties.stat) | Properties.cs:49:17:49:32 | object creation of type Properties | +| Properties.cs:51:9:51:24 | SSA call def(Properties.stat) | Properties.cs:51:9:51:24 | object creation of type Properties | +| Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | Properties.cs:61:17:61:17 | H | +| Properties.cs:61:23:61:23 | SSA param(i) | Properties.cs:61:23:61:23 | i | +| Properties.cs:63:16:63:18 | SSA def(i) | Properties.cs:63:16:63:18 | ...-- | +| Properties.cs:67:21:67:38 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:67:21:67:38 | this access | +| Properties.cs:72:20:72:37 | SSA untracked def(this.SingleAccessedProp) | Properties.cs:72:20:72:37 | this access | +| Properties.cs:73:13:73:32 | SSA def(f) | Properties.cs:73:13:73:32 | Properties f = ... | +| Properties.cs:74:23:74:54 | SSA def(a) | Properties.cs:74:23:74:54 | Action a = ... | +| Properties.cs:74:27:74:54 | SSA capture def(f) | Properties.cs:74:27:74:54 | (...) => ... | +| Properties.cs:75:23:75:35 | SSA def(b) | Properties.cs:75:23:75:35 | Action b = ... | +| Properties.cs:76:9:76:25 | SSA def(f.xs) | Properties.cs:76:9:76:25 | ... = ... | +| Properties.cs:77:9:77:11 | SSA call def(f.xs) | Properties.cs:77:9:77:11 | delegate call | +| Properties.cs:79:9:79:25 | SSA def(f.xs) | Properties.cs:79:9:79:25 | ... = ... | +| Properties.cs:81:9:81:22 | SSA def(this.xs) | Properties.cs:81:9:81:22 | ... = ... | +| Properties.cs:82:9:82:47 | SSA call def(f.xs) | Properties.cs:82:9:82:47 | call to method Select | +| Properties.cs:82:24:82:46 | SSA capture def(a) | Properties.cs:82:24:82:46 | (...) => ... | +| Properties.cs:83:9:83:22 | SSA def(this.xs) | Properties.cs:83:9:83:22 | ... = ... | +| Properties.cs:84:9:84:25 | SSA def(f.xs) | Properties.cs:84:9:84:25 | ... = ... | +| Properties.cs:85:24:85:46 | SSA capture def(b) | Properties.cs:85:24:85:46 | (...) => ... | +| Properties.cs:95:20:95:38 | SSA untracked def(this.NonTrivialProp) | Properties.cs:95:20:95:23 | this access | +| Properties.cs:98:16:98:31 | SSA untracked def(this.VirtualProp) | Properties.cs:98:16:98:19 | this access | +| Properties.cs:100:9:100:26 | SSA untracked def(this.VolatileField) | Properties.cs:100:9:100:12 | this access | +| Properties.cs:101:21:101:38 | SSA untracked def(this.VolatileField) | Properties.cs:101:21:101:24 | this access | +| Properties.cs:101:21:101:41 | SSA untracked def(this.VolatileField.xs) | Properties.cs:101:21:101:38 | access to field VolatileField | +| Properties.cs:106:37:106:37 | SSA param(p) | Properties.cs:106:37:106:37 | p | +| Properties.cs:108:10:108:10 | SSA entry def(this.Props) | Properties.cs:108:10:108:10 | K | +| Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props) | Properties.cs:108:10:108:10 | K | +| Properties.cs:108:10:108:10 | SSA entry def(this.Props.Props.xs) | Properties.cs:108:10:108:10 | K | +| Properties.cs:113:9:113:22 | SSA call def(this.Props) | Properties.cs:113:9:113:22 | call to method SetProps | +| Properties.cs:113:9:113:22 | SSA call def(this.Props.Props) | Properties.cs:113:9:113:22 | call to method SetProps | +| Properties.cs:113:9:113:22 | SSA qualifier def(this.Props.Props.xs) | Properties.cs:113:9:113:22 | call to method SetProps | +| Splitting.cs:3:18:3:18 | SSA param(b) | Splitting.cs:3:18:3:18 | b | +| Splitting.cs:7:13:7:19 | [b (line 3): true] SSA def(x) | Splitting.cs:7:13:7:19 | ... = ... | +| Splitting.cs:10:13:10:19 | [b (line 3): false] SSA def(x) | Splitting.cs:10:13:10:19 | ... = ... | +| Splitting.cs:22:18:22:18 | SSA param(b) | Splitting.cs:22:18:22:18 | b | +| Splitting.cs:29:13:29:19 | [b (line 22): false] SSA def(x) | Splitting.cs:29:13:29:19 | ... = ... | +| Splitting.cs:32:9:32:15 | [b (line 22): false] SSA def(x) | Splitting.cs:32:9:32:15 | ... = ... | +| Splitting.cs:32:9:32:15 | [b (line 22): true] SSA def(x) | Splitting.cs:32:9:32:15 | ... = ... | +| Splitting.cs:42:18:42:18 | SSA param(b) | Splitting.cs:42:18:42:18 | b | +| Splitting.cs:46:13:46:19 | [b (line 42): true] SSA def(x) | Splitting.cs:46:13:46:19 | ... = ... | +| Splitting.cs:49:13:49:19 | [b (line 42): false] SSA def(x) | Splitting.cs:49:13:49:19 | ... = ... | +| Test.cs:5:15:5:20 | SSA param(param1) | Test.cs:5:15:5:20 | param1 | +| Test.cs:5:67:5:72 | SSA param(param2) | Test.cs:5:67:5:72 | param2 | +| Test.cs:7:9:7:17 | SSA def(this.field) | Test.cs:7:9:7:17 | ... = ... | +| Test.cs:8:13:8:17 | SSA def(x) | Test.cs:8:13:8:17 | Int32 x = ... | +| Test.cs:13:13:13:15 | SSA def(x) | Test.cs:13:13:13:15 | ...++ | +| Test.cs:14:13:14:19 | SSA def(y) | Test.cs:14:13:14:19 | ... = ... | +| Test.cs:14:17:14:19 | SSA def(x) | Test.cs:14:17:14:19 | ++... | +| Test.cs:15:13:15:17 | SSA def(z) | Test.cs:15:13:15:17 | ... = ... | +| Test.cs:19:13:19:17 | SSA def(y) | Test.cs:19:13:19:17 | ... = ... | +| Test.cs:20:13:20:18 | SSA def(y) | Test.cs:20:13:20:18 | ... = ... | +| Test.cs:21:13:21:22 | SSA def(this.field) | Test.cs:21:13:21:22 | ... = ... | +| Test.cs:22:13:22:17 | SSA def(z) | Test.cs:22:13:22:17 | ... = ... | +| Test.cs:27:17:27:24 | SSA def(param1) | Test.cs:27:17:27:24 | ...++ | +| Test.cs:31:13:31:18 | SSA def(y) | Test.cs:31:13:31:18 | ... = ... | +| Test.cs:34:18:34:22 | SSA def(i) | Test.cs:34:18:34:22 | Int32 i = ... | +| Test.cs:34:33:34:35 | SSA def(i) | Test.cs:34:33:34:35 | ...++ | +| Test.cs:36:13:36:18 | SSA def(x) | Test.cs:36:13:36:18 | ... = ... | +| Test.cs:39:22:39:22 | SSA def(w) | Test.cs:39:22:39:22 | Int32 w | +| Test.cs:41:13:41:23 | SSA def(param1) | Test.cs:41:13:41:23 | ... = ... | +| Test.cs:46:10:46:10 | SSA entry def(this.field) | Test.cs:46:10:46:10 | g | +| Test.cs:46:16:46:18 | SSA param(in) | Test.cs:46:16:46:18 | in | +| Test.cs:50:13:50:20 | SSA def(out) | Test.cs:50:13:50:20 | ... = ... | +| Test.cs:54:13:54:20 | SSA def(out) | Test.cs:54:13:54:20 | ... = ... | +| Test.cs:57:9:57:17 | SSA def(this.field) | Test.cs:57:9:57:17 | ... = ... | +| Test.cs:68:45:68:45 | [exception: DivideByZeroException] SSA def(e) | Test.cs:68:45:68:45 | DivideByZeroException e | +| Tuples.cs:10:9:10:54 | SSA def(b) | Tuples.cs:10:9:10:54 | ... = ... | +| Tuples.cs:10:9:10:54 | SSA def(s) | Tuples.cs:10:9:10:54 | ... = ... | +| Tuples.cs:10:9:10:54 | SSA def(x) | Tuples.cs:10:9:10:54 | ... = ... | +| Tuples.cs:14:9:14:32 | SSA def(b) | Tuples.cs:14:9:14:32 | ... = ... | +| Tuples.cs:14:9:14:32 | SSA def(s) | Tuples.cs:14:9:14:32 | ... = ... | +| Tuples.cs:14:9:14:32 | SSA def(x) | Tuples.cs:14:9:14:32 | ... = ... | +| Tuples.cs:18:40:18:57 | SSA def(tuple) | Tuples.cs:18:40:18:57 | (Int32,(Boolean,String)) tuple = ... | +| Tuples.cs:20:9:20:34 | SSA def(this.Field) | Tuples.cs:20:9:20:34 | ... = ... | +| Tuples.cs:20:9:20:34 | SSA def(this.Property) | Tuples.cs:20:9:20:34 | ... = ... | +| Tuples.cs:23:9:23:37 | SSA def(x) | Tuples.cs:23:9:23:37 | ... = ... | +| Tuples.cs:25:13:25:28 | SSA def(t) | Tuples.cs:25:13:25:28 | Tuples t = ... | +| Tuples.cs:26:9:26:33 | SSA def(t.Field) | Tuples.cs:26:9:26:33 | ... = ... | +| Tuples.cs:26:9:26:33 | SSA def(this.Field) | Tuples.cs:26:9:26:33 | ... = ... | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql new file mode 100644 index 00000000000..e404aee7767 --- /dev/null +++ b/csharp/ql/test/library-tests/dataflow/ssa/SsaDefElement.ql @@ -0,0 +1,4 @@ +import csharp + +from Ssa::Definition def +select def, def.getElement() diff --git a/csharp/ql/test/library-tests/dispatch/CallGraph.expected b/csharp/ql/test/library-tests/dispatch/CallGraph.expected index ba6b3211313..a0c105c1c78 100644 --- a/csharp/ql/test/library-tests/dispatch/CallGraph.expected +++ b/csharp/ql/test/library-tests/dispatch/CallGraph.expected @@ -175,4 +175,5 @@ | ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:403:53:403:57 | M | | ViableCallable.cs:409:10:409:12 | Run | ViableCallable.cs:405:42:405:46 | M | | ViableCallable.cs:431:25:431:29 | M2 | ViableCallable.cs:442:17:442:23 | (...) => ... | -| ViableCallable.cs:436:9:436:9 | M | ViableCallable.cs:430:23:430:24 | M1 | +| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:430:23:430:24 | M1 | +| ViableCallable.cs:436:10:436:10 | M | ViableCallable.cs:431:25:431:29 | M2 | diff --git a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected index 0ea52d592c3..6779ec5a877 100644 --- a/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected +++ b/csharp/ql/test/library-tests/dispatch/GetADynamicTarget.expected @@ -399,5 +399,5 @@ | ViableCallable.cs:422:13:422:37 | call to method Mock | ViableCallable.Mock() | | ViableCallable.cs:424:9:424:21 | call to method M | C15.A4.M() | | ViableCallable.cs:424:9:424:21 | call to method M | C15.A5.M() | -| ViableCallable.cs:439:16:439:26 | call to method M1 | C16.M1(string) | +| ViableCallable.cs:439:9:439:19 | call to method M1 | C16.M1(string) | | ViableCallable.cs:442:9:442:24 | call to method M2 | C16.M2(Func) | diff --git a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs index fe32511ac19..e51c9c4b625 100644 --- a/csharp/ql/test/library-tests/dispatch/ViableCallable.cs +++ b/csharp/ql/test/library-tests/dispatch/ViableCallable.cs @@ -433,10 +433,10 @@ abstract class C16 class C17 : C16 { - int M(int i) + void M(int i) { // Viable callables: C16.M1() - return this.M1(""); + this.M1(""); // Viable callables: C16.M2() this.M2(() => i); diff --git a/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs b/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs index 9b8e37a7402..2a7cc3ae232 100644 --- a/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs +++ b/csharp/ql/test/query-tests/Security Features/CWE-209/ExceptionInformationExposure.cs @@ -5,7 +5,7 @@ using System.Web; public class StackTraceHandler : IHttpHandler { - + bool b; public void ProcessRequest(HttpContext ctx) { try @@ -54,7 +54,8 @@ public class StackTraceHandler : IHttpHandler // Method that may throw an exception public void doSomeWork() { - throw new Exception(); + if (b) + throw new Exception(); } public void log(string s, Exception e) diff --git a/javascript/ql/src/Statements/UselessConditional.ql b/javascript/ql/src/Statements/UselessConditional.ql index 0afdfa9f51e..115f16ef126 100644 --- a/javascript/ql/src/Statements/UselessConditional.ql +++ b/javascript/ql/src/Statements/UselessConditional.ql @@ -65,17 +65,24 @@ predicate isInitialParameterUse(Expr e) { } /** - * Holds if `e` directly uses the returned value from a function call that returns a constant boolean value. + * Holds if `e` directly uses the returned value from functions that return constant boolean values. */ predicate isConstantBooleanReturnValue(Expr e) { // unlike `SourceNode.flowsTo` this will not include uses we have refinement information for - exists(DataFlow::CallNode call | exists(call.analyze().getTheBooleanValue()) | - e = call.asExpr() - or - // also support return values that are assigned to variables - exists(SsaExplicitDefinition ssa | - ssa.getDef().getSource() = call.asExpr() and - ssa.getVariable().getAUse() = e + exists(string b | (b = "true" or b = "false") | + forex(DataFlow::CallNode call, Expr ret | + ret = call.getACallee().getAReturnedExpr() and + ( + e = call.asExpr() + or + // also support return values that are assigned to variables + exists(SsaExplicitDefinition ssa | + ssa.getDef().getSource() = call.asExpr() and + ssa.getVariable().getAUse() = e + ) + ) + | + ret.(BooleanLiteral).getValue() = b ) ) or diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected index b0d95f08153..5de81fba4b8 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.expected @@ -22,6 +22,9 @@ | UselessConditional.js:102:19:102:19 | x | This use of variable 'x' always evaluates to false. | | UselessConditional.js:103:23:103:23 | x | This use of variable 'x' always evaluates to false. | | UselessConditional.js:109:15:109:16 | {} | This expression always evaluates to true. | +| UselessConditional.js:129:6:129:24 | constantUndefined() | This call to constantUndefined always evaluates to false. | +| UselessConditional.js:135:6:135:32 | constan ... ined1() | This call to constantFalseOrUndefined1 always evaluates to false. | +| UselessConditional.js:139:6:139:32 | constan ... ined2() | This call to constantFalseOrUndefined2 always evaluates to false. | | UselessConditionalGood.js:58:12:58:13 | x2 | This use of variable 'x2' always evaluates to false. | | UselessConditionalGood.js:69:12:69:13 | xy | This use of variable 'xy' always evaluates to false. | | UselessConditionalGood.js:85:12:85:13 | xy | This use of variable 'xy' always evaluates to false. | diff --git a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js index ca0e5d19af9..f58152bf240 100644 --- a/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js +++ b/javascript/ql/test/query-tests/Statements/UselessConditional/UselessConditional.js @@ -109,4 +109,35 @@ async function awaitFlow(){ if ((x && {}) || y) {} // NOT OK }); +(function(){ + function constantFalse1() { + return false; + } + if (constantFalse1()) // OK + return; + + function constantFalse2() { + return false; + } + let constantFalse = unknown? constantFalse1 : constantFalse2; + if (constantFalse2()) // OK + return; + + function constantUndefined() { + return undefined; + } + if (constantUndefined()) // NOT OK + return; + + function constantFalseOrUndefined1() { + return unknown? false: undefined; + } + if (constantFalseOrUndefined1()) // NOT OK + return; + + let constantFalseOrUndefined2 = unknown? constantFalse1 : constantUndefined; + if (constantFalseOrUndefined2()) // NOT OK + return; + +}); // semmle-extractor-options: --experimental diff --git a/python/ql/src/Expressions/IsComparisons.qll b/python/ql/src/Expressions/IsComparisons.qll index 270c951f3cb..0c6343daefd 100644 --- a/python/ql/src/Expressions/IsComparisons.qll +++ b/python/ql/src/Expressions/IsComparisons.qll @@ -107,6 +107,20 @@ predicate invalid_portable_is_comparison(Compare comp, Cmpop op, ClassObject cls left.refersTo(obj) and right.refersTo(obj) and exists(ImmutableLiteral il | il.getLiteralObject() = obj) ) + and + /* OK to use 'is' when comparing with a member of an enum */ + not exists(Expr left, Expr right, AstNode origin | + comp.compares(left, op, right) and + enum_member(origin) | + left.refersTo(_, origin) or right.refersTo(_, origin) + ) } +private predicate enum_member(AstNode obj) { + exists(ClassObject cls, AssignStmt asgn | + cls.getASuperType().getName() = "Enum" | + cls.getPyClass() = asgn.getScope() and + asgn.getValue() = obj + ) +} diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp b/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp new file mode 100644 index 00000000000..92e3a57acbf --- /dev/null +++ b/python/ql/src/Security/CWE-732/WeakFilePermissions.qhelp @@ -0,0 +1,26 @@ + + + + +

    +When creating a file POSIX systems allow permissions to be specified +for owner, group and others separately. Permissions should be kept as +strict as possible, preventing access to the files contents by other users. +

    + +
    + + +

    +Restrict the file permissions of files to prevent any but the owner being able to read or write to that file +

    +
    + + +
  • +Wikipedia: +File system permissions. +
  • +
    + +
    diff --git a/python/ql/src/Security/CWE-732/WeakFilePermissions.ql b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql new file mode 100644 index 00000000000..a65b23845d6 --- /dev/null +++ b/python/ql/src/Security/CWE-732/WeakFilePermissions.ql @@ -0,0 +1,53 @@ +/** + * @name Overly permissive file permissions + * @description Allowing files to be readable or writable by users other than the owner may allow sensitive information to be accessed. + * @kind problem + * @id py/overly-permissive-file + * @problem.severity warning + * @sub-severity high + * @precision medium + * @tags external/cwe/cwe-732 + * security + */ +import python + +bindingset[p] +int world_permission(int p) { + result = p % 8 +} + +bindingset[p] +int group_permission(int p) { + result = (p/8) % 8 +} + +bindingset[p] +string access(int p) { + p%4 >= 2 and result = "writable" or + p%4 < 2 and p != 0 and result = "readable" +} + +bindingset[p] +string permissive_permission(int p) { + result = "world " + access(world_permission(p)) + or + world_permission(p) = 0 and result = "group " + access(group_permission(p)) +} + +predicate chmod_call(CallNode call, FunctionObject chmod, NumericObject num) { + any(ModuleObject os | os.getName() = "os").getAttribute("chmod") = chmod and + chmod.getACall() = call and call.getArg(1).refersTo(num) +} + +predicate open_call(CallNode call, FunctionObject open, NumericObject num) { + any(ModuleObject os | os.getName() = "os").getAttribute("open") = open and + open.getACall() = call and call.getArg(2).refersTo(num) +} + + +from CallNode call, FunctionObject func, NumericObject num, string permission +where + (chmod_call(call, func, num) or open_call(call, func, num)) + and + permission = permissive_permission(num.intValue()) +select call, "Overly permissive mask in " + func.getName() + " sets file to " + permission + "." diff --git a/python/ql/src/semmle/python/Variables.qll b/python/ql/src/semmle/python/Variables.qll index 21ccc43b545..49f0f1aa4f1 100644 --- a/python/ql/src/semmle/python/Variables.qll +++ b/python/ql/src/semmle/python/Variables.qll @@ -4,6 +4,13 @@ import python /** A variable, either a global or local variable (including parameters) */ class Variable extends @py_variable { + Variable() { + exists(string name | + variable(this, _, name) and + not name = "*" and not name = "$" + ) + } + /** Gets the identifier (name) of this variable */ string getId() { variable(this, _, result) diff --git a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll index ce80d74db3d..fba79d23c05 100644 --- a/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll +++ b/python/ql/src/semmle/python/dataflow/SsaDefinitions.qll @@ -26,7 +26,11 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable { } override string getName() { - result = this.(Variable).getId() + variable(this, _, result) + } + + Scope getScope() { + variable(this, result, _) } abstract ControlFlowNode getAnImplicitUse(); @@ -46,7 +50,7 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable { /* Add a use at the end of scope for all variables to keep them live * This is necessary for taint-tracking. */ - result = this.(Variable).getScope().getANormalExit() + result = this.getScope().getANormalExit() } override predicate hasDefiningNode(ControlFlowNode def) { @@ -107,7 +111,6 @@ class FunctionLocalVariable extends PythonSsaSourceVariable { } override ControlFlowNode getScopeEntryDefinition() { - not this.(LocalVariable).getId() = "*" and exists(Scope s | s.getEntryNode() = result | s = this.(LocalVariable).getScope() and @@ -146,7 +149,6 @@ class NonLocalVariable extends PythonSsaSourceVariable { } override CallNode redefinedAtCallSite() { - not this.(LocalVariable).getId() = "*" and result.getScope().getScope*() = this.(LocalVariable).getScope() } @@ -163,7 +165,6 @@ class ClassLocalVariable extends PythonSsaSourceVariable { } override ControlFlowNode getScopeEntryDefinition() { - not this.(LocalVariable).getId() = "*" and result = this.(LocalVariable).getScope().getEntryNode() } @@ -235,7 +236,6 @@ class ModuleVariable extends PythonSsaSourceVariable { } override ControlFlowNode getScopeEntryDefinition() { - not this.(GlobalVariable).getId() = "*" and exists(Scope s | s.getEntryNode() = result | /* Module entry point */ @@ -253,13 +253,6 @@ class ModuleVariable extends PythonSsaSourceVariable { this = scope.getOuterVariable(_) or this.(Variable).getAUse().getScope() = scope ) - or - this.(GlobalVariable).getId() = "*" and - exists(Scope s | - s.getEntryNode() = result and - this.(Variable).getScope() = s and - exists(ImportStar is | is.getScope() = s) - ) } override CallNode redefinedAtCallSite() { none() } @@ -307,6 +300,29 @@ class EscapingGlobalVariable extends ModuleVariable { } +class SpecialSsaSourceVariable extends PythonSsaSourceVariable { + + SpecialSsaSourceVariable() { + variable(this, _, "*") or variable(this, _, "$") + } + + override ControlFlowNode getAnImplicitUse() { + exists(ImportTimeScope s | + result = s.getANormalExit() and this.getScope() = s + ) + } + + override ControlFlowNode getScopeEntryDefinition() { + /* Module entry point */ + this.getScope().getEntryNode() = result + } + + override CallNode redefinedAtCallSite() { + result.(CallNode).getScope().getScope*() = this.(GlobalVariable).getScope() + } + +} + private predicate variable_or_attribute_defined_out_of_scope(Variable v) { exists(NameNode n | n.defines(v) and not n.getScope() = v.getScope()) or @@ -330,7 +346,7 @@ cached module SsaSource { /** Holds if `v` is used as the receiver in a method call. */ cached predicate method_call_refinement(Variable v, ControlFlowNode use, CallNode call) { - use = v.getAUse() and + use = v.getAUse() and call.getFunction().(AttrNode).getObject() = use } @@ -387,16 +403,17 @@ cached module SsaSource { /** Holds if the name of `var` refers to a submodule of a package and `f` is the entry point * to the __init__ module of that package. */ - cached predicate init_module_submodule_defn(Variable var, ControlFlowNode f) { + cached predicate init_module_submodule_defn(PythonSsaSourceVariable var, ControlFlowNode f) { + var instanceof GlobalVariable and exists(Module init | - init.isPackageInit() and exists(init.getPackage().getSubModule(var.getId())) and - var instanceof GlobalVariable and init.getEntryNode() = f and + init.isPackageInit() and exists(init.getPackage().getSubModule(var.getName())) and + init.getEntryNode() = f and var.getScope() = init ) } /** Holds if the `v` is in scope at a `from import ... *` and may thus be redefined by that statement */ - cached predicate import_star_refinement(Variable v, ControlFlowNode use, ControlFlowNode def) { + cached predicate import_star_refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { use = def and def instanceof ImportStarNode and ( @@ -443,7 +460,7 @@ cached module SsaSource { } -private predicate refinement(Variable v, ControlFlowNode use, ControlFlowNode def) { +private predicate refinement(PythonSsaSourceVariable v, ControlFlowNode use, ControlFlowNode def) { SsaSource::import_star_refinement(v, use, def) or SsaSource::attribute_assignment_refinement(v, use, def) @@ -456,5 +473,5 @@ private predicate refinement(Variable v, ControlFlowNode use, ControlFlowNode de or SsaSource::method_call_refinement(v, use, def) or - def = v.(PythonSsaSourceVariable).redefinedAtCallSite() and def = use + def = v.redefinedAtCallSite() and def = use } diff --git a/python/ql/src/semmle/python/pointsto/PointsTo.qll b/python/ql/src/semmle/python/pointsto/PointsTo.qll index dc57250e5d5..339de512084 100644 --- a/python/ql/src/semmle/python/pointsto/PointsTo.qll +++ b/python/ql/src/semmle/python/pointsto/PointsTo.qll @@ -119,7 +119,7 @@ module PointsTo { or exists(Module init | init = package.getInitModule().getModule() | - not exists(Variable v | v.getScope() = init | v.getId() = name or v.getId() = "*") + not exists(PythonSsaSourceVariable v | v.getScope() = init | v.getName() = name or v.getName() = "*") or exists(EssaVariable v, PointsToContext imp | v.getScope() = init and v.getName() = "*" and v.getAUse() = init.getANormalExit() | @@ -139,15 +139,15 @@ module PointsTo { var.getSourceVariable().getName() = name and ssa_variable_points_to(var, imp, obj, cls, orig) and imp.isImport() and - not obj = undefinedVariable() | + obj != undefinedVariable() | origin = origin_from_object_or_here(orig, exit) ) or not exists(EssaVariable var | var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = name) and exists(EssaVariable var, PointsToContext imp | - var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = "*" | + var.getAUse() = m.getANormalExit() and var.getName() = "*" | SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and - imp.isImport() and not obj = undefinedVariable() + imp.isImport() and obj != undefinedVariable() ) } @@ -257,7 +257,7 @@ module PointsTo { /** Holds if `f` is the instantiation of an object, `cls(...)`. */ cached predicate instantiation(CallNode f, PointsToContext context, ClassObject cls) { points_to(f.getFunction(), context, cls, _, _) and - not cls = theTypeType() and + cls != theTypeType() and Types::callToClassWillReturnInstance(cls) } @@ -312,7 +312,7 @@ module PointsTo { ) or exists(Object obj | - not obj = undefinedVariable() and + obj != undefinedVariable() and py_module_attributes(mod.getModule(), name, obj, _, _) ) and result = true or @@ -345,7 +345,7 @@ module PointsTo { private boolean package_exports_boolean(PackageObject pack, string name) { explicitly_imported(pack.submodule(name)) and ( - not exists(pack.getInitModule()) + pack.hasNoInitModule() or exists(ModuleObject init | pack.getInitModule() = init | @@ -381,9 +381,11 @@ module PointsTo { exists(Object value | points_to(guard.getLastNode(), context, value, _, _) | - guard.controls(b, true) and not value.booleanValue() = false + guard.controls(b, _) and value.maybe() or - guard.controls(b, false) and not value.booleanValue() = true + guard.controls(b, true) and value.booleanValue() = true + or + guard.controls(b, false) and value.booleanValue() = false ) or /* Assume the true edge of an assert is reachable (except for assert 0/False) */ @@ -402,9 +404,11 @@ module PointsTo { exists(ConditionBlock guard, Object value | points_to(guard.getLastNode(), context, value, _, _) | - guard.controlsEdge(pred, succ, true) and not value.booleanValue() = false + guard.controlsEdge(pred, succ, _) and value.maybe() or - guard.controlsEdge(pred, succ, false) and not value.booleanValue() = true + guard.controlsEdge(pred, succ, true) and value.booleanValue() = true + or + guard.controlsEdge(pred, succ, false) and value.booleanValue() = false ) } @@ -553,7 +557,7 @@ module PointsTo { /** Gets an object pointed to by a use (of a variable). */ private predicate use_points_to(NameNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) { exists(ObjectOrCfg origin_or_obj | - not value = undefinedVariable() and + value != undefinedVariable() and use_points_to_maybe_origin(f, context, value, cls, origin_or_obj) | origin = origin_from_object_or_here(origin_or_obj, f) ) @@ -577,7 +581,7 @@ module PointsTo { pragma [noinline] private predicate class_or_module_attribute(Object obj, string name, Object value, ClassObject cls, ObjectOrCfg orig) { /* Normal class attributes */ - Types::class_attribute_lookup(obj, name, value, cls, orig) and not cls = theStaticMethodType() and not cls = theClassMethodType() + Types::class_attribute_lookup(obj, name, value, cls, orig) and cls != theStaticMethodType() and cls != theClassMethodType() or /* Static methods of the class */ exists(CallNode sm | Types::class_attribute_lookup(obj, name, sm, theStaticMethodType(), _) and sm.getArg(0) = value and cls = thePyFunctionType() and orig = value) @@ -853,9 +857,13 @@ module PointsTo { exists(Object operand | points_to(f.getOperand(), context, operand, _, _) | - not operand.booleanValue() = true and value = theTrueObject() + operand.maybe() and value = theTrueObject() or - not operand.booleanValue() = false and value = theFalseObject() + operand.maybe() and value = theFalseObject() + or + operand.booleanValue() = false and value = theTrueObject() + or + operand.booleanValue() = true and value = theFalseObject() ) } @@ -1003,17 +1011,18 @@ module PointsTo { pragma [noinline] predicate call_points_to_builtin_function(CallNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) { exists(BuiltinCallable b | - not b = builtin_object("isinstance") and - not b = builtin_object("issubclass") and - not b = builtin_object("callable") and + b != builtin_object("isinstance") and + b != builtin_object("issubclass") and + b != builtin_object("callable") and f = get_a_call(b, context) and cls = b.getAReturnType() ) and f = origin and - if cls = theNoneType() then - value = theNoneObject() - else - value = f + ( + cls = theNoneType() and value = theNoneObject() + or + cls != theNoneType() and value = f + ) } /** Holds if call is to an object that always returns its first argument. @@ -1160,7 +1169,7 @@ module PointsTo { cls != theSuperType() and exists(Object o | /* list.__init__() is not a call to type.__init__() */ - not o instanceof ClassObject | + o.notClass() | points_to(n.(AttrNode).getObject(name), context, o, cls, _) ) or @@ -1203,12 +1212,14 @@ module PointsTo { /** Holds if `func` implicitly returns the `None` object */ predicate implicitly_returns(PyFunctionObject func, Object none_, ClassObject noneType) { - noneType = theNoneType() and not func.getFunction().isGenerator() and none_ = theNoneObject() and - ( - not exists(func.getAReturnedNode()) and exists(func.getFunction().getANormalExit()) - or - exists(Return ret | ret.getScope() = func.getFunction() and not exists(ret.getValue())) - ) + noneType = theNoneType() and none_ = theNoneObject() and + exists(Function f | + f = func.getFunction() and not f.isGenerator() + | + not exists(Return ret | ret.getScope() = f) and exists(f.getANormalExit()) + or + exists(Return ret | ret.getScope() = f and not exists(ret.getValue())) + ) } } @@ -1244,7 +1255,10 @@ module PointsTo { * is available to all functions. Although not strictly true, this gives less surprising * results in practice. */ pred_context.isMain() and pred_scope instanceof Module and succ_context.fromRuntime() and - not strictcount(pred_var.getSourceVariable().(Variable).getAStore()) > 1 + exists(Variable v | + v = pred_var.getSourceVariable() and + not strictcount(v.getAStore()) > 1 + ) ) or exists(NonEscapingGlobalVariable var | @@ -1571,8 +1585,8 @@ module PointsTo { deco = f.getADecorator().getAFlowNode() | exists(Object o | points_to(deco, _, o, _, _) | - not o = theStaticMethodType() and - not o = theClassMethodType() + o != theStaticMethodType() and + o != theClassMethodType() ) or not deco instanceof NameNode ) @@ -1589,7 +1603,7 @@ module PointsTo { | obj instanceof ClassObject and value = obj and cls = objcls or - not obj instanceof ClassObject and value = objcls and cls = Types::class_get_meta_class(objcls) + obj.notClass() and value = objcls and cls = Types::class_get_meta_class(objcls) ) } @@ -1707,16 +1721,17 @@ module PointsTo { call = def.getCall() and var = def.getSourceVariable() and context.untrackableCall(call) and - exists(PyFunctionObject modifier | + exists(PyFunctionObject modifier, Function f | + f = modifier.getFunction() and call = get_a_call(modifier, context) and - not modifies_escaping_variable(modifier, var) + not modifies_escaping_variable(f, var) ) ) } - private predicate modifies_escaping_variable(FunctionObject modifier, PythonSsaSourceVariable var) { + private predicate modifies_escaping_variable(Function modifier, PythonSsaSourceVariable var) { exists(var.redefinedAtCallSite()) and - modifier.getFunction().getBody().contains(var.(Variable).getAStore()) + modifier.getBody().contains(var.(Variable).getAStore()) } pragma [noinline] @@ -2320,7 +2335,7 @@ module PointsTo { or cls = theObjectType() and result = 0 or - exists(builtin_base_type(cls)) and not cls = theObjectType() and result = 1 + exists(builtin_base_type(cls)) and cls != theObjectType() and result = 1 or cls = theUnknownType() and result = 1 } @@ -2476,7 +2491,7 @@ module PointsTo { /** INTERNAL -- Use `ClassObject.declaredAttribute(name). instead. */ cached predicate class_declared_attribute(ClassObject owner, string name, Object value, ClassObject vcls, ObjectOrCfg origin) { /* Note that src_var must be a local variable, we aren't interested in the value that any global variable may hold */ - not value = undefinedVariable() and + value != undefinedVariable() and exists(EssaVariable var, LocalVariable src_var | var.getSourceVariable() = src_var and src_var.getId() = name and @@ -2561,7 +2576,12 @@ module PointsTo { or exists(int i | failed_inference(class_base_type(cls, i), _) and reason = "Failed inference for base class at position " + i) or - exists(int i | strictcount(class_base_type(cls, i)) > 1 and reason = "Multiple bases at position " + i) + exists(int i, Object base1, Object base2 | + base1 = class_base_type(cls, i) and + base2 = class_base_type(cls, i) and + base1 != base2 and + reason = "Multiple bases at position " + i + ) or exists(int i, int j | class_base_type(cls, i) = class_base_type(cls, j) and i != j and reason = "Duplicate bases classes") or @@ -2581,7 +2601,7 @@ module PointsTo { private ClassObject declared_meta_class(ClassObject cls) { exists(Object obj | - ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) | + ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) | result = obj or obj = unknownValue() and result = theUnknownType() @@ -2597,28 +2617,30 @@ module PointsTo { private boolean has_metaclass_var_metaclass(ClassObject cls) { exists(Object obj | - ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) | + ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) | obj = undefinedVariable() and result = false or obj != undefinedVariable() and result = true ) or - not exists(metaclass_var(cls)) and result = false + exists(Class pycls | + pycls = cls.getPyClass() and + not exists(metaclass_var(pycls)) and result = false + ) } private boolean has_declared_metaclass(ClassObject cls) { py_cobjecttypes(cls, _) and result = true or - not cls.isBuiltin() and result = has_six_add_metaclass(cls).booleanOr(has_metaclass_var_metaclass(cls)) } - private EssaVariable metaclass_var(ClassObject cls) { - result.getASourceUse() = cls.getPyClass().getMetaClass().getAFlowNode() + private EssaVariable metaclass_var(Class cls) { + result.getASourceUse() = cls.getMetaClass().getAFlowNode() or - major_version() = 2 and not exists(cls.getPyClass().getMetaClass()) and + major_version() = 2 and not exists(cls.getMetaClass()) and result.getName() = "__metaclass__" and - cls.getPyClass().(ImportTimeScope).entryEdge(result.getAUse(), _) + cls.(ImportTimeScope).entryEdge(result.getAUse(), _) } private ClassObject get_inherited_metaclass(ClassObject cls) { @@ -2628,7 +2650,7 @@ module PointsTo { exists(Object base | base = class_base_type(cls, _) and result = theUnknownType() | - not base instanceof ClassObject + base.notClass() or base = theUnknownType() ) diff --git a/python/ql/src/semmle/python/types/ClassObject.qll b/python/ql/src/semmle/python/types/ClassObject.qll index 2aa5e9f4a92..255e5c7d99c 100644 --- a/python/ql/src/semmle/python/types/ClassObject.qll +++ b/python/ql/src/semmle/python/types/ClassObject.qll @@ -392,6 +392,10 @@ class ClassObject extends Object { result.getFunction().refersTo(this) } + predicate notClass() { + none() + } + } /** The 'str' class. This is the same as the 'bytes' class for diff --git a/python/ql/src/semmle/python/types/ModuleObject.qll b/python/ql/src/semmle/python/types/ModuleObject.qll index 0bfa5037488..f323bd3cff3 100644 --- a/python/ql/src/semmle/python/types/ModuleObject.qll +++ b/python/ql/src/semmle/python/types/ModuleObject.qll @@ -226,6 +226,14 @@ class PackageObject extends ModuleObject { result.getModule() = this.getModule().getInitModule() } + /** Holds if this package has no `__init__.py` file. */ + predicate hasNoInitModule() { + not exists(Module m | + m.isPackageInit() and + m.getFile().getParent() = this.getPath() + ) + } + override predicate exportsComplete() { not exists(this.getInitModule()) or diff --git a/python/ql/src/semmle/python/types/Object.qll b/python/ql/src/semmle/python/types/Object.qll index 10b569ed076..d4e9b2b7811 100644 --- a/python/ql/src/semmle/python/types/Object.qll +++ b/python/ql/src/semmle/python/types/Object.qll @@ -151,6 +151,14 @@ class Object extends @py_object { ) } + final predicate maybe() { + not exists(this.booleanValue()) + } + + predicate notClass() { + any() + } + /** Holds if this object can be referred to by `longName` * For example, the modules `dict` in the `sys` module * has the long name `sys.modules` and the name `os.path.join` diff --git a/python/ql/src/semmle/python/web/tornado/Request.qll b/python/ql/src/semmle/python/web/tornado/Request.qll index bc28dba114d..ae19730e26e 100644 --- a/python/ql/src/semmle/python/web/tornado/Request.qll +++ b/python/ql/src/semmle/python/web/tornado/Request.qll @@ -15,16 +15,22 @@ class TornadoRequest extends TaintKind { result instanceof ExternalStringDictKind and ( name = "headers" or - name = "arguments" or name = "cookies" ) or result instanceof ExternalStringKind and ( - name = "path" or + name = "uri" or name = "query" or name = "body" ) + or + result instanceof ExternalStringSequenceDictKind and + ( + name = "arguments" or + name = "query_arguments" or + name = "body_arguments" + ) } } diff --git a/python/ql/src/semmle/python/web/twisted/Request.qll b/python/ql/src/semmle/python/web/twisted/Request.qll index 8be5db7bb4d..287a33ab1fe 100644 --- a/python/ql/src/semmle/python/web/twisted/Request.qll +++ b/python/ql/src/semmle/python/web/twisted/Request.qll @@ -19,8 +19,7 @@ class TwistedRequest extends TaintKind { or result instanceof ExternalStringKind and ( - name = "uri" or - name = "path" + name = "uri" ) } diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected index 502f88424c0..e0a751c4748 100644 --- a/python/ql/test/library-tests/PointsTo/new/Dataflow.expected +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.expected @@ -1,14 +1,11 @@ -| __init__.py:0 | *_0 = ScopeEntryDefinition | | __init__.py:0 | __name___0 = ScopeEntryDefinition | | __init__.py:0 | __package___0 = ScopeEntryDefinition | | __init__.py:0 | module2_0 = ImplicitSubModuleDefinition | | __init__.py:0 | moduleX_0 = ImplicitSubModuleDefinition | | __init__.py:0 | sys_0 = ScopeEntryDefinition | -| __init__.py:1 | *_1 = ImportStarRefinement(*_0) | | __init__.py:1 | __name___1 = ImportStarRefinement(__name___0) | | __init__.py:1 | __package___1 = ImportStarRefinement(__package___0) | | __init__.py:1 | sys_1 = ImportStarRefinement(sys_0) | -| __init__.py:2 | *_2 = ImportStarRefinement(*_1) | | __init__.py:2 | __name___2 = ImportStarRefinement(__name___1) | | __init__.py:2 | __package___2 = ImportStarRefinement(__package___1) | | __init__.py:2 | module_0 = ImportMember | @@ -498,7 +495,6 @@ | h_classes.py:52 | arg1_0 = ParameterDefinition | | h_classes.py:52 | n_0 = FunctionExpr | | h_classes.py:52 | self_0 = ParameterDefinition | -| i_imports.py:0 | *_0 = ScopeEntryDefinition | | i_imports.py:0 | BytesIO_0 = ScopeEntryDefinition | | i_imports.py:0 | StringIO_0 = ScopeEntryDefinition | | i_imports.py:0 | __name___0 = ScopeEntryDefinition | @@ -513,7 +509,6 @@ | i_imports.py:3 | a_0 = IntegerLiteral | | i_imports.py:4 | b_0 = IntegerLiteral | | i_imports.py:5 | c_0 = IntegerLiteral | -| i_imports.py:7 | *_1 = ImportStarRefinement(*_0) | | i_imports.py:7 | BytesIO_1 = ImportStarRefinement(BytesIO_0) | | i_imports.py:7 | StringIO_1 = ImportStarRefinement(StringIO_0) | | i_imports.py:7 | __name___1 = ImportStarRefinement(__name___0) | @@ -528,7 +523,6 @@ | i_imports.py:13 | argv_1 = ImportMember | | i_imports.py:17 | sys_1 = ImportExpr | | i_imports.py:23 | code_1 = ImportExpr | -| i_imports.py:27 | *_2 = ImportStarRefinement(*_1) | | i_imports.py:27 | __name___2 = ImportStarRefinement(__name___1) | | i_imports.py:27 | __package___2 = ImportStarRefinement(__package___1) | | i_imports.py:27 | a_2 = ImportStarRefinement(a_1) | diff --git a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql index 1761c3bc4ab..c2ed05aa9dc 100755 --- a/python/ql/test/library-tests/PointsTo/new/Dataflow.ql +++ b/python/ql/test/library-tests/PointsTo/new/Dataflow.ql @@ -4,5 +4,5 @@ import python import Util from EssaVariable v, EssaDefinition def -where def = v.getDefinition() +where def = v.getDefinition() and not v.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(def.getLocation(), "abdefghijknrs_"), v.getRepresentation() + " = " + def.getRepresentation() diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected b/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected index f518b462be1..212abaab73d 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.expected @@ -37,16 +37,6 @@ | g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v2' | runtime | | g_class_init.py:52 | self_3 | version | phi(self_1, self_2) | 'v3' | runtime | | g_class_init.py:54 | self_1 | version | Pi(self_0) [true] | 'v2' | runtime | -| i_imports.py:7 | *_1 | x | ImportStarRefinement(*_0) | float 1.0 | import | -| i_imports.py:7 | *_1 | y | ImportStarRefinement(*_0) | float 2.0 | import | -| i_imports.py:27 | *_2 | module1 | ImportStarRefinement(*_1) | Module code.test_package.module1 | import | -| i_imports.py:27 | *_2 | module2 | ImportStarRefinement(*_1) | Module code.test_package.module2 | import | -| i_imports.py:27 | *_2 | p | ImportStarRefinement(*_1) | int 1 | import | -| i_imports.py:27 | *_2 | q | ImportStarRefinement(*_1) | int 2 | import | -| i_imports.py:27 | *_2 | r | ImportStarRefinement(*_1) | Dict | import | -| i_imports.py:27 | *_2 | s | ImportStarRefinement(*_1) | NoneType None | import | -| i_imports.py:27 | *_2 | x | ImportStarRefinement(*_1) | float 1.0 | import | -| i_imports.py:27 | *_2 | y | ImportStarRefinement(*_1) | float 2.0 | import | | k_getsetattr.py:6 | self_0 | a | ParameterDefinition | float 7.0 | code/k_getsetattr.py:15 from runtime | | k_getsetattr.py:6 | self_0 | c | ParameterDefinition | int 2 | code/k_getsetattr.py:15 from runtime | | k_getsetattr.py:7 | self_1 | a | ArgumentRefinement(self_0) | int 0 | code/k_getsetattr.py:15 from runtime | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql index 4a2fac535cf..2a44c56ab1f 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaAttr.ql @@ -5,7 +5,7 @@ private import semmle.python.pointsto.PointsToContext import Util from EssaVariable var, string name, Object o, PointsToContext ctx -where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _) +where PointsTo::Test::ssa_variable_named_attribute_points_to(var, ctx, name, o, _, _) and not var.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(var.getDefinition().getLocation(), "abdfgikm"), var.getRepresentation(), name, var.getDefinition().getRepresentation(), repr(o), ctx diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected index aff87febe79..f8f4ad3a98b 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaUses.expected +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.expected @@ -1,4 +1,3 @@ -| __init__.py:0 | *_2 | Exit node for Module code.test_package.__init__ | | __init__.py:0 | __name___0 | Exit node for Module code.__init__ | | __init__.py:0 | __name___0 | Exit node for Module code.package.__init__ | | __init__.py:0 | __name___2 | Exit node for Module code.test_package.__init__ | @@ -12,11 +11,9 @@ | __init__.py:0 | moduleX_1 | Exit node for Module code.package.__init__ | | __init__.py:0 | module_0 | Exit node for Module code.package.__init__ | | __init__.py:0 | sys_2 | Exit node for Module code.test_package.__init__ | -| __init__.py:1 | *_0 | ControlFlowNode for from module1 import * | | __init__.py:1 | __name___0 | ControlFlowNode for from module1 import * | | __init__.py:1 | __package___0 | ControlFlowNode for from module1 import * | | __init__.py:1 | sys_0 | ControlFlowNode for from module1 import * | -| __init__.py:2 | *_1 | ControlFlowNode for from module2 import * | | __init__.py:2 | __name___1 | ControlFlowNode for from module2 import * | | __init__.py:2 | __package___1 | ControlFlowNode for from module2 import * | | __init__.py:2 | sys_1 | ControlFlowNode for from module2 import * | diff --git a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql index 681ac79bc78..53d48cc36e1 100644 --- a/python/ql/test/library-tests/PointsTo/new/SsaUses.ql +++ b/python/ql/test/library-tests/PointsTo/new/SsaUses.ql @@ -5,5 +5,5 @@ import semmle.python.pointsto.PointsTo import Util from EssaVariable var, ControlFlowNode use -where use = var.getAUse() +where use = var.getAUse() and not var.getSourceVariable() instanceof SpecialSsaSourceVariable select locate(use.getLocation(), "abdeghjks_"), var.getRepresentation(), use.toString() diff --git a/python/ql/test/library-tests/ast/Child.expected b/python/ql/test/library-tests/ast/Child.expected deleted file mode 100644 index afcceb30240..00000000000 --- a/python/ql/test/library-tests/ast/Child.expected +++ /dev/null @@ -1,257 +0,0 @@ -| test.py:0:0 | Module test | test.py:5:1 | ClassDef | -| test.py:0:0 | Module test | test.py:11:1 | FunctionDef | -| test.py:0:0 | Module test | test.py:14:1 | FunctionDef | -| test.py:0:0 | Module test | test.py:17:1 | FunctionDef | -| test.py:0:0 | Module test | test.py:51:1 | FunctionDef | -| test.py:2:2 | deco1() | test.py:2:2 | deco1 | -| test.py:2:2 | deco1() | test.py:3:1 | deco2()() | -| test.py:3:1 | deco2() | test.py:3:2 | deco2 | -| test.py:3:1 | deco2()() | test.py:3:1 | deco2() | -| test.py:3:1 | deco2()() | test.py:4:2 | Attribute() | -| test.py:4:2 | Attribute | test.py:4:2 | Attribute | -| test.py:4:2 | Attribute | test.py:4:2 | deco3 | -| test.py:4:2 | Attribute() | test.py:4:2 | Attribute | -| test.py:4:2 | Attribute() | test.py:5:1 | ClassExpr | -| test.py:5:1 | Class C | test.py:7:5 | FunctionDef | -| test.py:5:1 | ClassDef | test.py:2:2 | deco1() | -| test.py:5:1 | ClassDef | test.py:5:7 | C | -| test.py:5:1 | ClassExpr | test.py:5:1 | Class C | -| test.py:5:1 | ClassExpr | test.py:5:9 | Base | -| test.py:7:5 | Function __init__ | test.py:7:18 | self | -| test.py:7:5 | Function __init__ | test.py:8:9 | Pass | -| test.py:7:5 | FunctionDef | test.py:7:5 | FunctionExpr | -| test.py:7:5 | FunctionDef | test.py:7:9 | __init__ | -| test.py:7:5 | FunctionExpr | test.py:7:5 | Function __init__ | -| test.py:10:1 | Attribute() | test.py:10:2 | Attribute | -| test.py:10:1 | Attribute()() | test.py:10:1 | Attribute() | -| test.py:10:1 | Attribute()() | test.py:11:1 | FunctionExpr | -| test.py:10:2 | Attribute | test.py:10:2 | deco4 | -| test.py:11:1 | Function f | test.py:12:5 | Pass | -| test.py:11:1 | FunctionDef | test.py:10:1 | Attribute()() | -| test.py:11:1 | FunctionDef | test.py:11:5 | f | -| test.py:11:1 | FunctionExpr | test.py:11:1 | Function f | -| test.py:14:1 | Function f | test.py:14:7 | pos0 | -| test.py:14:1 | Function f | test.py:14:13 | pos1 | -| test.py:14:1 | Function f | test.py:14:20 | args | -| test.py:14:1 | Function f | test.py:14:28 | kwargs | -| test.py:14:1 | Function f | test.py:15:5 | Pass | -| test.py:14:1 | FunctionDef | test.py:14:1 | FunctionExpr | -| test.py:14:1 | FunctionDef | test.py:14:5 | f | -| test.py:14:1 | FunctionExpr | test.py:14:1 | Function f | -| test.py:17:1 | Function simple_stmts | test.py:18:5 | Pass | -| test.py:17:1 | Function simple_stmts | test.py:19:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:19:13 | Delete | -| test.py:17:1 | Function simple_stmts | test.py:19:20 | Pass | -| test.py:17:1 | Function simple_stmts | test.py:20:5 | If | -| test.py:17:1 | Function simple_stmts | test.py:24:5 | AssignStmt | -| test.py:17:1 | Function simple_stmts | test.py:44:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:45:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:46:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:47:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:48:5 | ExprStmt | -| test.py:17:1 | Function simple_stmts | test.py:49:5 | ExprStmt | -| test.py:17:1 | FunctionDef | test.py:17:1 | FunctionExpr | -| test.py:17:1 | FunctionDef | test.py:17:5 | simple_stmts | -| test.py:17:1 | FunctionExpr | test.py:17:1 | Function simple_stmts | -| test.py:19:5 | ExprStmt | test.py:19:5 | foo() | -| test.py:19:5 | foo() | test.py:19:5 | foo | -| test.py:19:13 | Delete | test.py:19:17 | x | -| test.py:20:5 | If | test.py:20:8 | thing | -| test.py:20:5 | If | test.py:21:9 | For | -| test.py:21:9 | For | test.py:21:13 | a | -| test.py:21:9 | For | test.py:21:18 | b | -| test.py:21:9 | For | test.py:22:13 | Pass | -| test.py:24:5 | AssignStmt | test.py:24:5 | tmp | -| test.py:24:5 | AssignStmt | test.py:25:9 | Yield | -| test.py:25:9 | Yield | test.py:25:15 | Tuple | -| test.py:25:15 | Tuple | test.py:25:15 | IntegerLiteral | -| test.py:25:15 | Tuple | test.py:26:9 | name | -| test.py:25:15 | Tuple | test.py:27:9 | Attribute | -| test.py:25:15 | Tuple | test.py:28:9 | BinaryExpr | -| test.py:25:15 | Tuple | test.py:29:9 | BinaryExpr | -| test.py:25:15 | Tuple | test.py:30:9 | BinaryExpr | -| test.py:25:15 | Tuple | test.py:31:9 | Attribute | -| test.py:25:15 | Tuple | test.py:32:9 | Subscript | -| test.py:25:15 | Tuple | test.py:33:9 | Lambda | -| test.py:25:15 | Tuple | test.py:34:9 | BoolExpr | -| test.py:25:15 | Tuple | test.py:35:9 | Compare | -| test.py:25:15 | Tuple | test.py:36:9 | DictComp | -| test.py:25:15 | Tuple | test.py:37:9 | SetComp | -| test.py:25:15 | Tuple | test.py:38:9 | ListComp | -| test.py:25:15 | Tuple | test.py:39:9 | List | -| test.py:25:15 | Tuple | test.py:40:9 | Dict | -| test.py:25:15 | Tuple | test.py:41:9 | Tuple | -| test.py:25:15 | Tuple | test.py:42:10 | Tuple | -| test.py:27:9 | Attribute | test.py:27:9 | attr | -| test.py:28:9 | BinaryExpr | test.py:28:9 | a | -| test.py:28:9 | BinaryExpr | test.py:28:13 | b | -| test.py:29:9 | BinaryExpr | test.py:29:9 | IntegerLiteral | -| test.py:29:9 | BinaryExpr | test.py:29:13 | IntegerLiteral | -| test.py:30:9 | BinaryExpr | test.py:30:9 | FloatLiteral | -| test.py:30:9 | BinaryExpr | test.py:30:15 | IntegerLiteral | -| test.py:31:9 | Attribute | test.py:31:9 | Attribute | -| test.py:31:9 | Attribute | test.py:31:9 | a | -| test.py:32:9 | Attribute | test.py:32:9 | a() | -| test.py:32:9 | Subscript | test.py:32:9 | Attribute | -| test.py:32:9 | Subscript | test.py:32:15 | c | -| test.py:32:9 | a() | test.py:32:9 | a | -| test.py:33:9 | Function lambda | test.py:33:16 | x | -| test.py:33:9 | Function lambda | test.py:33:19 | Return | -| test.py:33:9 | Lambda | test.py:33:9 | Function lambda | -| test.py:33:19 | BinaryExpr | test.py:33:19 | x | -| test.py:33:19 | BinaryExpr | test.py:33:21 | IntegerLiteral | -| test.py:33:19 | Return | test.py:33:19 | BinaryExpr | -| test.py:34:9 | BoolExpr | test.py:34:9 | p | -| test.py:34:9 | BoolExpr | test.py:34:14 | BoolExpr | -| test.py:34:14 | BoolExpr | test.py:34:14 | q | -| test.py:34:14 | BoolExpr | test.py:34:20 | BinaryExpr | -| test.py:34:20 | BinaryExpr | test.py:34:20 | r | -| test.py:34:20 | BinaryExpr | test.py:34:24 | s | -| test.py:35:9 | Compare | test.py:35:9 | a | -| test.py:35:9 | Compare | test.py:35:13 | b | -| test.py:35:9 | Compare | test.py:35:17 | c | -| test.py:35:9 | Compare | test.py:35:22 | IntegerLiteral | -| test.py:36:9 | DictComp | test.py:36:9 | Function dictcomp | -| test.py:36:9 | DictComp | test.py:36:26 | x | -| test.py:36:9 | For | test.py:36:9 | .0 | -| test.py:36:9 | For | test.py:36:9 | For | -| test.py:36:9 | For | test.py:36:11 | ExprStmt | -| test.py:36:9 | For | test.py:36:21 | z | -| test.py:36:9 | For | test.py:36:32 | y | -| test.py:36:9 | For | test.py:36:37 | z | -| test.py:36:9 | Function dictcomp | test.py:36:9 | .0 | -| test.py:36:9 | Function dictcomp | test.py:36:9 | For | -| test.py:36:11 | ExprStmt | test.py:36:11 | Yield | -| test.py:36:11 | Tuple | test.py:36:11 | IntegerLiteral | -| test.py:36:11 | Tuple | test.py:36:15 | y | -| test.py:36:11 | Yield | test.py:36:11 | Tuple | -| test.py:37:9 | For | test.py:37:9 | .0 | -| test.py:37:9 | For | test.py:37:9 | For | -| test.py:37:9 | For | test.py:37:12 | ExprStmt | -| test.py:37:9 | For | test.py:37:22 | z | -| test.py:37:9 | For | test.py:37:33 | y | -| test.py:37:9 | For | test.py:37:38 | z | -| test.py:37:9 | Function setcomp | test.py:37:9 | .0 | -| test.py:37:9 | Function setcomp | test.py:37:9 | For | -| test.py:37:9 | SetComp | test.py:37:9 | Function setcomp | -| test.py:37:9 | SetComp | test.py:37:27 | x | -| test.py:37:12 | ExprStmt | test.py:37:12 | Yield | -| test.py:37:12 | Tuple | test.py:37:12 | IntegerLiteral | -| test.py:37:12 | Tuple | test.py:37:15 | y | -| test.py:37:12 | Yield | test.py:37:12 | Tuple | -| test.py:38:9 | For | test.py:38:9 | .0 | -| test.py:38:9 | For | test.py:38:11 | ExprStmt | -| test.py:38:9 | For | test.py:38:20 | y | -| test.py:38:9 | Function listcomp | test.py:38:9 | .0 | -| test.py:38:9 | Function listcomp | test.py:38:9 | For | -| test.py:38:9 | ListComp | test.py:38:9 | Function listcomp | -| test.py:38:9 | ListComp | test.py:38:25 | z | -| test.py:38:11 | BinaryExpr | test.py:38:11 | y | -| test.py:38:11 | BinaryExpr | test.py:38:14 | IntegerLiteral | -| test.py:38:11 | ExprStmt | test.py:38:11 | Yield | -| test.py:38:11 | Yield | test.py:38:11 | BinaryExpr | -| test.py:42:10 | Tuple | test.py:42:10 | IntegerLiteral | -| test.py:44:5 | ExprStmt | test.py:44:5 | foo() | -| test.py:44:5 | foo() | test.py:44:5 | foo | -| test.py:44:5 | foo() | test.py:44:9 | IntegerLiteral | -| test.py:45:5 | ExprStmt | test.py:45:5 | foo() | -| test.py:45:5 | foo() | test.py:45:5 | foo | -| test.py:45:5 | foo() | test.py:45:9 | Keyword | -| test.py:45:9 | Keyword | test.py:45:11 | IntegerLiteral | -| test.py:46:5 | ExprStmt | test.py:46:5 | foo() | -| test.py:46:5 | foo() | test.py:46:5 | foo | -| test.py:46:5 | foo() | test.py:46:9 | IntegerLiteral | -| test.py:46:5 | foo() | test.py:46:11 | IntegerLiteral | -| test.py:46:5 | foo() | test.py:46:13 | Starred | -| test.py:46:13 | Starred | test.py:46:14 | t | -| test.py:47:5 | ExprStmt | test.py:47:5 | foo() | -| test.py:47:5 | foo() | test.py:47:5 | foo | -| test.py:47:5 | foo() | test.py:47:9 | IntegerLiteral | -| test.py:47:5 | foo() | test.py:47:11 | Keyword | -| test.py:47:5 | foo() | test.py:47:15 | Starred | -| test.py:47:11 | Keyword | test.py:47:13 | IntegerLiteral | -| test.py:47:15 | Starred | test.py:47:16 | t | -| test.py:48:5 | ExprStmt | test.py:48:5 | foo() | -| test.py:48:5 | foo() | test.py:48:5 | foo | -| test.py:48:5 | foo() | test.py:48:9 | IntegerLiteral | -| test.py:48:5 | foo() | test.py:48:11 | Keyword | -| test.py:48:5 | foo() | test.py:48:15 | Starred | -| test.py:48:5 | foo() | test.py:48:18 | DictUnpacking | -| test.py:48:11 | Keyword | test.py:48:13 | IntegerLiteral | -| test.py:48:15 | Starred | test.py:48:16 | t | -| test.py:48:18 | DictUnpacking | test.py:48:20 | d | -| test.py:49:5 | ExprStmt | test.py:49:5 | f() | -| test.py:49:5 | f() | test.py:49:5 | f | -| test.py:49:5 | f() | test.py:49:7 | DictUnpacking | -| test.py:49:7 | DictUnpacking | test.py:49:9 | d | -| test.py:51:1 | Function compound_stmts | test.py:52:5 | If | -| test.py:51:1 | Function compound_stmts | test.py:56:5 | While | -| test.py:51:1 | Function compound_stmts | test.py:61:5 | For | -| test.py:51:1 | Function compound_stmts | test.py:63:5 | With | -| test.py:51:1 | Function compound_stmts | test.py:65:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:69:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:73:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:77:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:81:5 | Try | -| test.py:51:1 | Function compound_stmts | test.py:87:5 | Try | -| test.py:51:1 | FunctionDef | test.py:51:1 | FunctionExpr | -| test.py:51:1 | FunctionDef | test.py:51:5 | compound_stmts | -| test.py:51:1 | FunctionExpr | test.py:51:1 | Function compound_stmts | -| test.py:52:5 | If | test.py:52:8 | cond | -| test.py:52:5 | If | test.py:53:9 | Return | -| test.py:52:5 | If | test.py:55:9 | Raise | -| test.py:53:9 | Return | test.py:53:16 | x | -| test.py:55:9 | Raise | test.py:55:15 | y | -| test.py:56:5 | While | test.py:56:11 | True | -| test.py:56:5 | While | test.py:57:9 | If | -| test.py:57:9 | If | test.py:57:12 | cond | -| test.py:57:9 | If | test.py:58:13 | Break | -| test.py:57:9 | If | test.py:60:13 | Continue | -| test.py:61:5 | For | test.py:61:9 | x | -| test.py:61:5 | For | test.py:61:14 | y | -| test.py:61:5 | For | test.py:62:9 | Pass | -| test.py:63:5 | With | test.py:63:5 | With | -| test.py:63:5 | With | test.py:63:10 | a | -| test.py:63:5 | With | test.py:63:15 | b | -| test.py:63:5 | With | test.py:63:18 | c | -| test.py:63:5 | With | test.py:63:23 | d | -| test.py:63:5 | With | test.py:64:9 | ExprStmt | -| test.py:64:9 | ExprStmt | test.py:64:9 | body | -| test.py:65:5 | Try | test.py:66:9 | ExprStmt | -| test.py:65:5 | Try | test.py:67:5 | ExceptStmt | -| test.py:66:9 | ExprStmt | test.py:66:9 | t1 | -| test.py:67:5 | ExceptStmt | test.py:68:9 | ExprStmt | -| test.py:68:9 | ExprStmt | test.py:68:9 | e1 | -| test.py:69:5 | Try | test.py:70:9 | ExprStmt | -| test.py:69:5 | Try | test.py:71:5 | ExceptStmt | -| test.py:70:9 | ExprStmt | test.py:70:9 | t2 | -| test.py:71:5 | ExceptStmt | test.py:71:12 | Exception | -| test.py:71:5 | ExceptStmt | test.py:72:9 | ExprStmt | -| test.py:72:9 | ExprStmt | test.py:72:9 | e2 | -| test.py:73:5 | Try | test.py:74:9 | ExprStmt | -| test.py:73:5 | Try | test.py:75:5 | ExceptStmt | -| test.py:74:9 | ExprStmt | test.py:74:9 | t3 | -| test.py:75:5 | ExceptStmt | test.py:75:12 | Exception | -| test.py:75:5 | ExceptStmt | test.py:75:25 | ex | -| test.py:75:5 | ExceptStmt | test.py:76:9 | ExprStmt | -| test.py:76:9 | ExprStmt | test.py:76:9 | e3 | -| test.py:77:5 | Try | test.py:78:9 | ExprStmt | -| test.py:77:5 | Try | test.py:80:9 | ExprStmt | -| test.py:78:9 | ExprStmt | test.py:78:9 | t4 | -| test.py:80:9 | ExprStmt | test.py:80:9 | f4 | -| test.py:81:5 | Try | test.py:82:9 | ExprStmt | -| test.py:81:5 | Try | test.py:83:5 | ExceptStmt | -| test.py:81:5 | Try | test.py:86:9 | ExprStmt | -| test.py:82:9 | ExprStmt | test.py:82:9 | t5 | -| test.py:83:5 | ExceptStmt | test.py:83:12 | Exception | -| test.py:83:5 | ExceptStmt | test.py:83:25 | ex | -| test.py:83:5 | ExceptStmt | test.py:84:9 | ExprStmt | -| test.py:84:9 | ExprStmt | test.py:84:9 | e5 | -| test.py:86:9 | ExprStmt | test.py:86:9 | f5 | -| test.py:87:5 | Try | test.py:88:9 | ExprStmt | -| test.py:87:5 | Try | test.py:90:9 | Try | -| test.py:88:9 | ExprStmt | test.py:88:9 | t6 | -| test.py:90:9 | Try | test.py:91:13 | ExprStmt | -| test.py:90:9 | Try | test.py:93:13 | ExprStmt | -| test.py:91:13 | ExprStmt | test.py:91:13 | t7 | -| test.py:93:13 | ExprStmt | test.py:93:13 | f7 | diff --git a/python/ql/test/library-tests/ast/Child.ql b/python/ql/test/library-tests/ast/Child.ql deleted file mode 100644 index a0ae5909f08..00000000000 --- a/python/ql/test/library-tests/ast/Child.ql +++ /dev/null @@ -1,7 +0,0 @@ -import python -import semmle.python.TestUtils - -from AstNode p, AstNode c -where p.getAChildNode() = c -select compact_location(p), p.toString(), compact_location(c), c.toString() - diff --git a/python/ql/test/library-tests/ast/test.py b/python/ql/test/library-tests/ast/test.py deleted file mode 100644 index 320efb1fdcc..00000000000 --- a/python/ql/test/library-tests/ast/test.py +++ /dev/null @@ -1,94 +0,0 @@ - -@deco1 -@deco2() -@deco3.attr1.attr2 -class C(Base): - - def __init__(self): - pass - -@deco4.attr() -def f(): - pass - -def f(pos0, pos1, *args, **kwargs): - pass - -def simple_stmts(): - pass - foo() ; del x; pass - if thing: - for a in b: - pass - #Expressions - tmp = ( - yield 3, - name, - attr.attrname, - a + b, - 3 & 4, - 3.0 * 4, - a.b.c.d, - a().b[c], - lambda x: x+1, - p or q and r ^ s, - a < b > c in 5, - { 1 : y for z in x for y in z}, - { (1, y) for z in x for y in z}, - [ y**2 for y in z ], - [], - {}, - (), - (1,), - ) - foo(1) - foo(a=1) - foo(1,2,*t) - foo(1,a=1,*t) - foo(1,a=1,*t,**d) - f(**d) - -def compound_stmts(): - if cond: - return x - else: - raise y - while True: - if cond: - break - else: - continue - for x in y: - pass - with a as b, c as d: - body - try: - t1 - except: - e1 - try: - t2 - except Exception: - e2 - try: - t3 - except Exception as ex: - e3 - try: - t4 - finally: - f4 - try: - t5 - except Exception as ex: - e5 - finally: - f5 - try: - t6 - finally: - try: - t7 - finally: - f7 - diff --git a/python/ql/test/query-tests/Expressions/eq/expressions_test.py b/python/ql/test/query-tests/Expressions/eq/expressions_test.py index 2ffac276553..46b7a0c4005 100644 --- a/python/ql/test/query-tests/Expressions/eq/expressions_test.py +++ b/python/ql/test/query-tests/Expressions/eq/expressions_test.py @@ -24,7 +24,7 @@ -#ODASA-4519 + #OK as we are using identity tests for unique objects V2 = "v2" V3 = "v3" @@ -85,3 +85,21 @@ def both_sides_known(zero_based="auto", query_id=False): if zero_based is False: # False positive here pass +#Avoid depending on enum back port for Python 2 tests: +class Enum(object): + pass + +class MyEnum(Enum): + + memberA = None + memberB = 10 + memberC = ("Hello", "World") + +def comp_enum(x): + if x is MyEnum.memberA: + return + if x is MyEnum.memberB: + return + if x is MyEnum.memberC: + return + diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected new file mode 100644 index 00000000000..3bfb6fe4f88 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.expected @@ -0,0 +1,7 @@ +| test.py:7:1:7:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. | +| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. | +| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | +| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. | +| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. | diff --git a/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref new file mode 100644 index 00000000000..9e177187c49 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/WeakFilePermissions.qlref @@ -0,0 +1 @@ +Security/CWE-732/WeakFilePermissions.ql diff --git a/python/ql/test/query-tests/Security/CWE-732/options b/python/ql/test/query-tests/Security/CWE-732/options new file mode 100644 index 00000000000..b63c517ee29 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/options @@ -0,0 +1,2 @@ +semmle-extractor-options: --max-import-depth=2 -p ../lib +optimize: true diff --git a/python/ql/test/query-tests/Security/CWE-732/test.py b/python/ql/test/query-tests/Security/CWE-732/test.py new file mode 100644 index 00000000000..273311ef3e7 --- /dev/null +++ b/python/ql/test/query-tests/Security/CWE-732/test.py @@ -0,0 +1,16 @@ +import os +import stat + +file = 'semmle/important_secrets' + + +os.chmod(file, 0o7) # BAD +os.chmod(file, 0o77) # BAD +os.chmod(file, 0o777) # BAD +os.chmod(file, 0o600) # GOOD +os.chmod(file, 0o550) # BAD +os.chmod(file, stat.S_IRWXU) # GOOD +os.chmod(file, stat.S_IWGRP) # BAD +os.chmod(file, 400) # BAD -- Decimal format. + +os.open(file, 'w', 0o704) # BAD diff --git a/python/ql/test/query-tests/Security/lib/os/__init__.py b/python/ql/test/query-tests/Security/lib/os/__init__.py index 9cbc1f15559..d7a7ca0eb38 100644 --- a/python/ql/test/query-tests/Security/lib/os/__init__.py +++ b/python/ql/test/query-tests/Security/lib/os/__init__.py @@ -3,3 +3,9 @@ def system(cmd, *args, **kwargs): def popen(cmd, *args, **kwargs): return None + +def chmod(path, mode): + pass + +def open(path, flags, mode): + pass